Поведение GWT RequestFactory STRANGE: нет сообщений об ошибках

У меня есть проблема, и я не могу понять, что происходит... Новичок в 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 не применяется...


person Răzvan Petruescu    schedule 27.07.2012    source источник


Ответы (2)


Почему это каким-то образом не отправляется клиенту как ошибка/исключение?

Это. "S": [false] указывает на то, что первый (и единственный) вызов метода (помните, RequestContext — это пакет!) не удался. Будет вызван метод onFailure вызова Receiver.

Затем "F": true из ServerFailure сообщает, что это фатальная ошибка, поэтому реализация Receiver#onFailure по умолчанию выдает RuntimeException. Однако, поскольку вы вообще не используете Receiver, ничего не происходит, и ошибка просто игнорируется.

Обратите внимание, что пакетный запрос сам по себе выполнен успешно, поэтому глобальный Receiver (тот, который вы передадите RequestContext#fire) вызовет свой метод onSuccess.
Также обратите внимание, что Request#fire(Receiver) — это сокращение для Request#to(Receiver), за которым следует RequestContext#fire() (без аргумента). ).

Почему это не регистрируется Hibernate?

Этого я не знаю, извините.

Почему сгенерированный Spring Roo код (как я уже сказал, используемый в качестве основы) работает без проявления этой проблемы?

Хорошо, давайте рассмотрим основную причину исключения: сущность загружается вашим Locator (или статическим методом findXxx класса сущности), а затем для экземпляра вызывается метод persist. Если вы не используете один и тот же сеанс JPA EntityManager/Hibernate в методах find и persist, у вас возникнет проблема.
Request Factory предполагает, что вы будете использовать шаблон open session in view для преодолеть это. К сожалению, я не знаю, какой код генерирует Spring Roo.

person Thomas Broyer    schedule 27.07.2012

Что касается шаблона open session in view, упомянутого Томасом, просто добавьте определения этого фильтра в свой web.xml, чтобы включить шаблон в вашем приложении Spring:

<filter>
    <filter-name>
        Spring OpenEntityManagerInViewFilter
    </filter-name>
    <filter-class>
         org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
person Ümit    schedule 30.07.2012
comment
Хорошо, спасибо Юмит, я нашел проблему, и она была связана с некоторыми неправильно сформированными файлами конфигурации ... Однако один вопрос остается открытым: почему Hibernate не сообщает об ошибках? На чем-то подобном я обязательно должен увидеть трассировку стека... - person Răzvan Petruescu; 31.07.2012
comment
Я не могу вспомнить на 100%, но у меня аналогичная настройка Hibernate + JPA2 + Requestfactory, и когда я столкнулся с этой проблемой, я полагаю, что в методе сохранения было создано исключение, и я зарегистрировал его в консоли GWT. Не уверен, что мое приложение Spring также зарегистрировало его. - person Ümit; 31.07.2012