Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring+Jersey transactional annotation

Created boilerplate project to expose RESTful API to JPA enabled database. It's using the following versions:
- Spring 3.2.6
- Hibernate 4.3.0
- Jersey 2.5.1
I finally was able to get them playing together, but still some question remains. Here's one of the most puzzling things (see excerpt from REST service class)

@Service
@Path("resources")
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
@Transactional
public class ResourceServices extends AbstractServices<Resource> {
...
}

if class is annotated with @Service, @Transactional annotation is ignored and transaction for the methods is not started. However, when changed to @Component, everything works fine. Couldn't figure out, why.

The entire project can be seen here

like image 521
AndreiM Avatar asked Jan 14 '14 01:01

AndreiM


People also ask

What does @transactional annotation do in Spring?

The @Transactional annotation makes use of the attributes rollbackFor or rollbackForClassName to rollback the transactions, and the attributes noRollbackFor or noRollbackForClassName to avoid rollback on listed exceptions. The default rollback behavior in the declarative approach will rollback on runtime exceptions.

What does the @transactional annotation mean?

The @Transactional annotation is metadata that specifies that an interface, class, or method must have transactional semantics; for example, "start a brand new read-only transaction when this method is invoked, suspending any existing transaction".

What is the use of @transactional annotation in Java?

Transactional annotation provides the application the ability to declaratively control transaction boundaries on CDI managed beans, as well as classes defined as managed beans by the Java EE specification, at both the class and method level where method level annotations override those at the class level.

What are the default @transactional settings?

The default @Transactional settings are: The propagation setting is PROPAGATION_REQUIRED. The isolation level is ISOLATION_DEFAULT. The transaction is read/write.


2 Answers

I got puzzled by this as well, but finally figured this out.

The jersey-spring module will only import @Component beans from your context. There literally is a beanClass.isAnnotationPresent(Component.class) check in SpringComponentProvider.

Otherwise it appears to only create half-baked request-scoped instances of the bean (I traced this with Thread.dumpStack in service constructor). They seem to have dependency injection, but not AOP.

There's a number of JIRA items already in Jersey's issue tracker: JERSEY-2495, JERSEY-2059, JERSEY-2301

UPDATE: My pull request for these has been merged, this should be fixed in Jersey 2.11.

like image 144
Konrad Garus Avatar answered Oct 01 '22 20:10

Konrad Garus


As mentioned in another answer SpringComponentProvider gets a bean created by Jersey and registers it in the Spring context, but in this case you don't get Spring AOP.

I managed to get it working with AOP the other way around: the bean is created by Spring (so in fact it is a proxy because of AOP) and then is registered in Jersey.

But I had to fix a bug in Jersey's ModelHelper class: https://github.com/jersey/jersey/pull/90

Without this fix Jersey was not able to find the @Path annotation in the Spring proxy.

This is the basic structure:

public class MyApplication extends ResourceConfig {
    @Inject
    public MyApplication(ServletContext servletContext) {
        super(JSONController.class, XSSSecurityFilter.class, JacksonFeature.class);
        WebApplicationContext springFactory = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        // TODO: scan entire Spring factory for beans annotated with @Path and register them, so we don't need to do this manually.
        // Letting Jersey register the beans does not work because in this case Spring will not intercept the calls.
        register(springFactory.getBean(UserServiceFacade.class));
    }
}
like image 44
Constantino Cronemberger Avatar answered Oct 01 '22 20:10

Constantino Cronemberger