У меня есть проблема, и я не могу понять, что происходит... Новичок в GWT, работаю над личным проектом.
Окружающая обстановка:
Проект maven с двумя модулями
один модуль является «моделью» и имеет зависимости Hibernate, HSQLDB и Spring. HSQLDB работает встроенным в памяти, настроенным из Spring applicationContext.xml
другой модуль — это «веб» и имеет все зависимости от GWT.
Приложение построено с использованием кода, сгенерированного Spring Roo, в качестве основы, позже модифицированного и расширенного.
Проблема в том, что при редактировании некоторых полей объекта и нажатии кнопки "Сохранить" ничего не происходит. Нет проблем при создании нового экземпляра объекта, только при редактировании изменение некоторого поля и нажатие «сохранить» в основном переопределяет новые значения. Итак, я начал тщательно отлаживать клиентский код, включил гибернацию и подробное ведение журналов Spring, но все равно… ничего.
Потом я сделал неожиданное (для себя) открытие. Проверяя полезную нагрузку ответа GWT, я увидел это:
{"S":[false],"O": [{"T":"663_uruC_g7F5h5IXBGvTP3BBKM=","V":"MS4w","S":"IjMi","O":"UPDATE"}],"I":[{"F":true,"M":"Server Error: org.hibernate.PersistentObjectException: detached entity passed to persist: com.myvdm.server.domain.Document; nested exception is javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.myvdm.server.domain.Document"}]}
Ага, отдельная сущность перешла на сохранение!!! Обратите внимание, что код клиента gwt использует этот фрагмент для вызова службы:
requestContext.persist().using(прокси);
Возможно, это может вызвать исключение, и вызов merge() может решить проблему, однако читайте дальше, чтобы ответить на вопрос 3...
Возникают три вопроса:
- Почему это каким-то образом не отправляется клиенту как ошибка/исключение?
- Почему это не регистрируется Hibernate?
- Почему сгенерированный Spring Roo код (как я уже сказал, используемый в качестве основы) работает без проявления этой проблемы?
Большое спасибо,
Ожидание некоторых мнений/предложений.
ОТРЕДАКТИРОВАНО ПОСЛЕ ОТВЕТА Т. БРОЙЕРА::
Привет, Томас, спасибо за ответ.
У меня есть собственный класс, который реализует RequestTransport и реализует send(). Вот как я собрал полезную нагрузку ответа. Реализация следующая:
public void send(String payload, final TransportReceiver receiver) {
TransportReceiver myReceiver = new TransportReceiver() {
@Override
public void onTransportSuccess(String payload) {
try {
receiver.onTransportSuccess(payload);
} finally {
eventBus.fireEvent(new RequestEvent(RequestEvent.State.RECEIVED));
}
}
@Override
public void onTransportFailure(ServerFailure failure) {
try {
receiver.onTransportFailure(failure);
} finally {
eventBus.fireEvent(new RequestEvent(RequestEvent.State.RECEIVED));
}
}
};
try {
wrapped.send(payload, myReceiver);
} finally {
eventBus.fireEvent(new RequestEvent(RequestEvent.State.SENT));
}
}
Вот код, который выполняется при нажатии кнопки «Сохранить» в режиме редактирования:
RequestContext requestContext = editorDriver.flush();
if (editorDriver.hasErrors()) {
return;
}
requestContext.fire(new Receiver<Void>() {
@Override
public void onFailure(ServerFailure error) {
if (editorDriver != null) {
setWaiting(false);
super.onFailure(error);
}
}
@Override
public void onSuccess(Void ignore) {
if (editorDriver != null) {
editorDriver = null;
exit(true);
}
}
@Override
public void onConstraintViolation(Set<ConstraintViolation<?>> errors) {
if (editorDriver != null) {
setWaiting(false);
editorDriver.setConstraintViolations(errors);
}
}
});
Исходя из того, что вы сказали, следует вызвать метод onSuccess(), и он вызывается
Итак, как мне выделить именно тот код, который создает проблему? У меня есть этот метод, который создает новый контекст запроса, чтобы сохранить объект
@Override
protected RequestContext createSaveRequestContextFor(DocumentProxy proxy) {
DocumentRequestContext request = requests.documentRequestContext();
request.persist().using(proxy);
return request;
}
и вот как это называется::
editorDriver.edit(getProxy(), createSaveRequestContextFor(getProxy()));
Что касается проблемы Spring, вы говорите, что между двумя последующими запросами, find() и persist(), JPA entityManager не должен быть закрыт. Я все еще изучаю это, но после того, как я нажимаю кнопку редактирования, я вижу сообщение «org.springframework.orm.jpa.EntityManagerFactoryUtils — Closing JPA EntityManager», и это неправильно, возможно, аннотация @Transactional не применяется...