Невозможно сохранить сущности с 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):

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, не зная текущей транзакции.

Другие вопросы по тегам