Невозможно сохранить сущности с tynamo-resteasy, когда служба находится в пакете автообнаружения
В моем открытии интеграции tynamo и restteasy я столкнулся с проблемой сохранения данных, которую я частично решил (поэтому я частично поделюсь ею;)). Руководство пользователя находится здесь: http://docs.codehaus.org/display/TYNAMO/tapestry-resteasy+guide
Я написал службу отдыха, которая позволяет "пользователям" регистрироваться в моей системе:
package com.myorg.mobile.pushup.rest;
//[...]
/**
* bla blah obfuscated pretty comments.
*
* @author jrrevy
*
*/
@Path("/user")
public class UserResource {
private Session session;
/**
* Constructeur du service
*
* @param session
* Hibernate session
*/
public UserResource(Session session) {
this.session = session;
}
/**
* Lecture de tous les utilisateurs
*
* @return une liste des utilisateurs existants
*/
@GET
@Produces("application/json")
public List<User> getAllDomains() {
return session.createCriteria(User.class).list();
}
/**
* Create User.
*
* @param user
* user to create
* @return a Web Response
*/
@POST
@PUT
@Produces({ "application/xml", "application/json" })
public Response createOrUpdate(User user) {
session.saveOrUpdate(user);
return Response.ok().build();
}
Доступ к базе данных работает хорошо (я возвращаю своих пользователей, выполняя команду INSERT INTO в журналах), но эта служба никогда ничего не сохраняет. Кажется, что транзакция никогда не совершается.
Я использую 0.3.0 версии tapestry-model-hibernate и tapestry-resteasy:
<dependencies>
<dependency>
<groupId>org.tynamo</groupId>
<artifactId>tapestry-model-hibernate</artifactId>
<version>0.3.0</version>
</dependency>
<dependency>
<groupId>org.tynamo</groupId>
<artifactId>tapestry-resteasy</artifactId>
<version>0.3.0</version>
</dependency>
</dependencies>
Смотрите мой ответ выше, но, пожалуйста, скажите мне, если вы нашли лучший способ.
2 ответа
Согласно этой теме: http://osdir.com/ml/java-tynamo-user/2012-04/msg00005.html, это просто проблема COMMIT:).
В стандартном контексте транзакция обрабатывается страницей, которая вызвала сервис. В подходе REST эта работа должна выполняться самой службой.
Идея в том, чтобы действительно превратить ваш REST-сервис с автоматическим обнаружением в настоящий гобеленовый IOC.
1 - отодвиньте его от автообнаружения
Переместите его в пакет услуг (или любой, кто разрешает привязку Tapestry, а не в пакет автоматического обнаружения rest):
- как советует Алехандро Скандроли в документации: http://docs.codehaus.org/pages/viewpage.action?pageId=151847035
- и в этом посте: класс xxx не содержит общедоступного конструктора, необходимого для автоматического построения, когда xxx становится сервисом Tapestry
2 - Извлечь интерфейс
Извлеките интерфейс и поместите в него аннотации + CommitAfter, где вы хотите иметь дело с транзакцией.
package com.myorg.mobile.pushup.services.user;
@Path("/user")
public interface IUserResource {
/**
* Lecture de tous les utilisateurs
*
* @return une List des utilisateurs existants
*/
@GET
@Produces("application/json")
List<User> getAllDomains();
/**
* Méthode d'enregistrement / MAJ d'un utilisateur.
*
* @param user
* l'utilisateur à créer
* @return
*/
@POST
@PUT
@Produces({ "application/xml", "application/json" })
@Consumes({ "application/xml", "application/json" })
@CommitAfter
Response registerOrUpdate(User user);
}
Удалить аннотацию по реализации
package com.myorg.mobile.pushup.services.user.impl;
public class HibernateUserResourceImpl implements IUserResource {
/* (non-Javadoc)
*/
public List<User> getAllDomains() {
return session.createCriteria(User.class).list();
}
/* (non-Javadoc)
*/
Response registerOrUpdate(User user);
session.saveOrUpdate(user);
return Response.ok().build();
}
3 - внести свой вклад как единый ресурс
public class AppModule {
public static void bind(ServiceBinder binder) {
binder.bind(IUserResource.class, HibernateUserResourceImpl.class);
}
/**
* Contributions to the RESTeasy main Application, insert all your RESTeasy
* singletons services here.
*/
@Contribute(javax.ws.rs.core.Application.class)
public static void configureRestResources(Configuration<Object> singletons,
IUserResource userResource) {
singletons.add(userResource);
}
}
4. Сообщите аннотированным методам, что они являются транзакционными.
public class AppModule {
@Match("*Resource*")
public static void adviseTransactionally(
HibernateTransactionAdvisor advisor, MethodAdviceReceiver receiver) {
advisor.addTransactionCommitAdvice(receiver);
}
Вы можете добавить другие зависимости, если вы предпочитаете использовать JPATransactionAdvision вместо Hibernate:
<dependency>
<groupId>org.tynamo</groupId>
<artifactId>tapestry-jpa-core</artifactId>
<version>2.0.1</version>
</dependency>
5. Вывод
Это решение работает для меня, но, насколько я понимаю, это фактически единственный способ сделать это.
Alejandro> Если ты читаешь эти строки, скажи мне, если есть другой (самый короткий) способ, я прав:)
Вы можете использовать реализацию HibernateSessionManager (заданную внутри зависимости tapestry-hibernate), чтобы получить сеанс и мгновенно зафиксировать данные, как показано ниже,
@Inject
HibernateSessionManager hibernateSessionManager;
public void saveOrUpdate(MyEntity instance) {
Session session = hibernateSessionManager.getSession();
session.saveOrUpdate(instance);
hibernateSessionManager.commit();
session.flush();
}
Здесь вы не можете закрыть сессию. Поскольку сеанс является общим, если вы попытаетесь закрыть сеанс, у вас может появиться исключение, например "сеанс гибернации закрыт".
Здесь также используется транзакция, поэтому вы можете только зафиксировать транзакцию, используя функцию commit(), заданную в hibernateSessionManager, не зная текущей транзакции.