Java – Transactions and Subresources with JAX-RS

javaresttransaction

I'm porting an existing application RESTful API to a Java web framework — I don't actually care which — but it's proving hard to get the basics right.

The core of the problem appears to be getting the bridge between JAX-RS and the database so that transactions work. The API uses subresources a lot, and the way JAX-RS appears to work involves returning a new locator. Now that's a nice pattern, but it means there is nowhere that makes an effective bound on the transaction, so the @Transactional annotations become a problem. I'd really like them to be scoped to the request somehow, but none of the frameworks I've tried seem to make that easy, or even possible.

It's a kind of a three body problem. I can do transactions and queries fine by pushing them into a repository layer, but then I'd have to not use subresources. Or I can do subresources and even queries nicely but then there is nowhere nice for the transactions to happen. Basically I can have any two of transactions, subresources, and complex queries, but I need all three.

So far, I've tried to get this working with Guice + Jersey + Querydsl, and with Spring Data and Spring REST. They all seem entirely based on the idea that each endpoint can be @Transactional, and (usually) that it is a simple CRUD API on tables. I have a very nice front end already built. and I can't see any good reason to totally rewrite it because Java makes the services awkward to build.

I know somehow I need to get the transactions tied to the request, and use DTOs anyway so I'm happy with that, but I can't find any way to make that happen. Does anybody have any useful pointers, templates, advice?

Best Answer

If JAX-RS is not a requirement, then I'd suggest looking at Restlet. It uses conveyor architecture, so nesting resources into other resources is not a problem - see hierarchical URIs. When integrating with Spring, you typically define root SpringBeanRouter, in which you put actual resources, in each of which you can put another routers, and so on.

You can wrap every method of every resource by just defining top-level request filter, which could use Spring's transaction template or something similar. Or, since you're not required to return locators, you can just go with @Transactional annotation on methods of (sub)resources.

See org.restlet.ext.spring package for details.