Tuesday 27 January 2009

JAX-RS as the one Java web framework to rule them all?

One of the things about Java that sometimes gets made fun of is the huge number of Java based web frameworks. There certainly are many, of all shapes and sizes! I suppose there are quite a lot of different shapes and sizes of web applications out there but it sometimes seems like there's a 1-1 mapping between applications and frameworks :).

Picking the right web framework is probably a managers nightmare (Which one to pick? Pick the wrong one and we might end up using a duff dead framework that few developers know etc?). But it has lead to a ton of innovation in the web framework space. On balance I think competition and innovation are good things.

I'm a big Rails fan, I think its a stunning piece of work and one of the most impressive open source frameworks created in the last 10 years which together with Ruby, Erb and Rake is a good alternative to Servlets + JSP + JSTL + Spring + Hibernate + WebFrameworkOfYourChoice + SiteMesh/Tiles + Ant/Maven + a few other bits all in a surpringly small and easy to grok codebase.

JAX-RS came along initially as a way of writing RESTful services on the Java platform; using annotations and loose coupling to bind resource beans and their public methods to URIs, HTTP methods and MIME content type negotiation. I've said before I think its awesome, one of the most impressive JSRs we've had.

From the perspective of the controller layer I actually prefer JAX-RS to Rails routes.rb & controllers as
  • the URI bindings are local to the resource beans which can be arbitrarily nested which makes refactoring much easier and avoids the complex routes.rb file with regex switches (I try and avoid regex whenever I can :)
  • the loose coupling between the objects returned by the resource methods and the actual entity providers is clean; helping the application programmer focus on returning DTOs and letting the framework deal with the XML / JSON /Atom / multi-part-form marshalling & data binding stuff really helps. e.g. its easy to drop in support for new representations in a DRY way without changing the code of your resource beans (controllers), you can just modify an annotation
  • static typing can be a handy thing when binding URIs and parameters to your controller. e.g. having String, integer, Date fields and parameters helps you having to explicitly convert things in your controller
There's lots of other stuff thats great in Rails though :-) but this post isn't a JAX-RS versus Rails post really - its focussing on the world of Java web frameworks for Java developers and the impact of JAX-RS.

So whats interesting is - if you want to build a web application with RESTful services (e.g. a human facing website with computer facing XML/JSON APIs) why would you use JAX-RS and another web framework? Why not just use JAX-RS as the web framework? So recently I've been musing, could JAX-RS be the one Java web framework to rule them all?

JAX-RS works well with dependency injection frameworks such as Spring, Guice, GuiceyFruit or JBossMC - you can basically pick whichever one you prefer. It also does all the heavily lifting of binding URIs and HTTP methods to resource beans and their methods along with supporting content type negotiation, headers and etags elegantly. For implementing great RESTful services in Java I've never seen anything close to touching it. The main question is what features are missing from JAX-RS being the main web framework?

Incidentally in this post I'm ignoring the server-side UI type frameworks like Wicket, Tapestry, JSF et al. I'm focussing on web frameworks that spend most of their time rendering HTML / XML / JSON and not building complex server side UI stuff and treating the browser as a kinda dumb terminal with the real UI work being done on the server side. Having had a horrid time using Tapestry and Hibernate together on some projects in the past, I'm kinda over the whole concept of server side UI web frameworks personally (I'm putting my flame-proof suite on now). I kinda think if you want to do complex rich web UIs, use wizards or complex flows, just use GWT or JavaScript on the client (or Flex/Flash for video or crazy highly graphical widgets) and keep the server side fairly simple and very RESTful. (But lets leave that discussion for another day... :)

In this post I'm only really considering frameworks like Struts, Stripes, SpringMVC etc. Thankfully WebWork and Struts merged together so at least there's been some consolidation in the space - and certainly Struts and Stripes are now kinda similar (and not too disimilar from SpringMVC). I wonder if JAX-RS will lead to further consolidation with web frameworks adding themselves as JAX-RS extensions?

So whats is missing from JAX-RS to be able to use just it for your entire web app and set of RESTful services and not have to use it with Struts/Stripes/SpringMVC and have to map some URIs into the web framework and some to JAX-RS?

Right now today there are definitely some holes; though currently I don't think there's that much missing. Here's my list of things I think are missing and how we could add them - I'm very interested in hearing if there's anything you'd particularly miss from Struts/Stripes/SpringMVC/whatever; please blog about it or post a comment and I'll do a follow up post!

Implict & Explicit Views
One great feature of Jersey is the support for Implicit and Explicit Views. Update: here's a link describing implict/explicit views. It basically allows the controller to delegate to the view layer (JSP/Velocity/Freemarker/GXP or whatever) using a default naming convention to find the template files in a directory named after the resource bean's class name and if required - the URI being requested. So a given Resource bean could have an index.jsp and edit.jsp templates for example - and referring to ${it.foo} inside the template would extract the foo property of the resource bean (you can override what 'it' is if you like but the resource bean is a very reasonable default).

Maybe the easiest way to understand implicit/explicit views is to look at the bookstore example in the Jersey distro; its basically the glue between JAX-RS resources and templates.

However there are some issues (which are being addressed particularly by the helpful folks on the Jersey list, particularly Marc and Paul) which basically revolve around having implicit/explicit views and (say) XML/JSON representations on the same resource bean using the same URIs and getting JAX-RS to pick the right one.

For example the URI "/customers" might return a HTML page for most web browsers but return XML/JSON if folks want to specify those MIME types in their Accept header. Right now Jersey tends to favour returning XML/JSON (long story but basically more specific URI paths are preferred over implicit views).

I'm pretty sure some kind of @ImplicitProduces annotation to allow implicit views to be associated to MIME types along with a higher priority/quality ranking specified in the next feature would solve pretty much all the issues with implicit/explicit views though am sure folks can think of other improvements...

Better Content Negotiation Support
It would be nice to see these issues resolved to be able to use RFC 2296 to be able to raise and lower the priorities (or quality) of the different representations.

e.g. you might want to prefer to return HTML over XML/JSON so unless folks ask specifically just for XML or JSON you return HTML.

Bizarrely Safari uses an Accept header of
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
which kinda means it prefers to render XML over HTML (despite rendering XML as plain text! Truly bizarre - what was Steve smoking that day :). Most web apps I know of would rather return HTML by default :)

So you might want to specify something like this on a resource to declare that you want to return HTML by default for most users...
@ImplicitProduces("text/html;q=1.0")
@Produces("text/xml;q=0.5, application/xml;q=0.5; application/json;q=0.5")
public class MyResource {
...
}
Those MIME Strings could be static final constants BTW to keep things DRY and not have to repeat a ton of MIME expressions throughout your resource beans and making it real easy to add a new MIME type to your code without changing your controller methods.

You could argue the out of the box rankings for HTML should be 1.0 and XML/JSON something lower, say 0.9 or 0.5 as thats what most folks would want.

Dealing with static content
The Servlet spec is a tad smelly in this area (and even in servlet 3.0) of not easily allowing you to mark URI patterns as being handled by the container (e.g. for static content or for JSP files etc) and mapping all of the rest to your default servlet. Hopefully as Paul suggests we can get around this using servlet filters in Jersey; but it'd be nicer if there was a better fix for this. (Rails wins here hands down with using regex to map URIs to controllers). But this is more a servlet issue than JAX-RS / web framework.

Multipart support
Having support for Struts style form beans; binding a multipart to a bean is very handy. MrStruts himself has contributed jersey-multipart which goes most of the way there. Allowing direct binding with any bean to avoid having to use the MultiPart class directly would certainly help.

Standard JAX-RS client API like Jersey's
While not that relevant directly to web applications; being able to implement a REST service by invoking other RESTful services - or being able to test easily any RESTful service using an API like Jersey's client - while reusing the cool entity providers on both client and server side - would rock.

GWT and JAX-RS client integration
If you're building JAX-RS services and want a rich web client then GWT is a great solution; you can reuse all your Java code on the client and server side and its very easy to debug the whole application in a single JVM in your Java IDE.

GWT ships with its own RPC mechanism and there are various REST libraries for GWT such as gwt-rest it'd be nice if there was an easy way to reuse the same DTOs used on the server side like you can with Jersey's client library from inside GWT. Using JAXB inside GWT is probably non-feasaible :) but it should be pretty easy to just use GWT serialization and then support it as an entity provider in the JAX-RS runtime. (Is there a MIME type for GWT serialisation I wonder :).

Basically as an application developer it should be trivial to be able to reuse RESTful resources in JAX-RS inside the GWT client reusing all those DTOs if you want to.

Update: some other suggestions
Julio Faerman mentioned on the Jersey list mentioned the need for better validation. So maybe we could integrate the validation layer from Struts/Stripes into JAX-RS? Or use the the Bean Validation API (JSR 303)?

Also Julio and Jon in the comments mentioned the need for managing conversational state so integrating Web Beans (JSR 299) as an option for bijection of conversational state on resource beans sounds a good possibility.

What else?
Those are the things I can think of so far. Can you think of any others? What are there features in your favourite Struts/Stripes/SpringMVC/whatever framework on the server that you really can't live without?

I'd love to hear others thoughts; do you think I'm smoking crack or do you agree? :)

36 comments:

Jerome Louvel said...

Hi James,

I agree that REST is radically redefining the expectations from Web frameworks.

With Restlet, we are pushing the REST concepts at maximum. The exact same API is both client and server capable, as well as multi-protocols (still centered around HTTP semantics of course).

We have both a class-oriented API (inspired from Servlet) and an annotation-oriented API (implementing JAX-RS). Both approaches can even be combined if wanted.

We also have ported our API to GWT recently.

Cheers,
Jerome

James Strachan said...

Hi Jerome

Agreed. Its interesting Restlet embraced JAX-RS and builds on it. I'd not realised Restlet has been ported to GWT - am taking a deep look now! :)

I'm interested to see if the GWT restlet client can reuse the same DTOs as the Java server side...

Jerome Louvel said...

James,

Glad I have spiked your interest! :)

Regarding the reuse of DTO classes, we are planning a transparent marshalling between DTOs and JSON on both sides (client GWT and server Java).

For now, you could use a complementary GWT project like Rocket-GWT.

See comments at the end of this RFE: "Enhance Restlet-GWT module".

Best regards,
Jerome

a said...

Hey James,

I've been playing around with Seam recently. I took a look at it in the 1.x days and just felt it was too complicated. However, 2.x has gotten cleaner and I'm pretty impressed. Take a look at the example hotel room booking application. Implementing something like that with any other framework (specifically the 'conversations' context) has never been done before quite like it. I've even grown to be ok with the RichFaces implementation in Seam given how much it does for you. GWT is great, but too much of the view is coded up in Java making it too difficult for designers to touch easily.

Talking with Gavin and reading about how jsr299 is progressing, I'm even more impressed with the future of what will be Seam3.

We've come a long ways since the Turbine days.

Stefane Fermigier said...

Great post, tanks !

JAX-RS is now the foundation of the Nuxeo WebEngine, the simple to use REST fronted to the Nuxeo content management infrastructure.

So far, we're very happy with our choice of Jax-RS.

Unknown said...

Interesting post.

Paul's got a nice entry on the implicit/explicit views (http://blogs.sun.com/sandoz/entry/mvcj).

-Arul

Unknown said...

+1 - Standard JAX-RS client API like Jersey's

-Arul

Sam said...

Re: Nuxeo

I think your web server falls victim to what James describes for Safari in his webpost. When I go to your site it just downloads it as a file.

Sam

James Strachan said...

Jon - thanks for the tip; I'll take another look at Seam3. The use of JSF put me right off Seam :)

I guess given WebBeans being a standard spec with multiple implementations (the Apache ones coming along right?) then a JAX-RS provider could reuse the same WebBeans bijection engine to manage conversational state - so you could easily mix and match WebBeans with JAX-RS - without having to use JSF.

But then with hi-rest, would we need to manage conversational state on the server? :)

/me ducks hi-low rest flamefest

a said...

Take a look at this:

http://docs.jboss.org/webbeans/reference/1.0/en-US/pdf/guide.pdf

Honestly, I don't care about rest, hi-rest, low-rest, middle-rest, JSF, RichFaces, blah blah blah anymore. I just want something that works amazingly with a minimal amount of coding, fuss and configuration. Is that too much to ask for? =)

Staff Software Engineer at Google said...

RESTEasy has a proxy-based REST client, which basically means that you can get a fully functional Java object based on an Interface with JAX-RS annotations and and base URL. Still, I also added a client API that's similar Jersey's client API to RESTEasy... The Jersey API is definitely a "+1"

James Strachan said...

Thanks sduskis, I spotted the proxy client API in RESTeasy the other day - I really like it. Am not sure how it works when doing things like if-modified checks with etags and the like - I guess the proxy implementation could deal with that?

I'd love to see something like the Jersey client API standardized; then maybe the approach of making a smart proxy on top of that using a custom interface with JAX-RS annotations could be adopted - either by the JAX-RS standard or just as a common implementation approach.

Stephen Colebourne said...

You've actually beat me to this one. I agree that JAX-RS shows all the hallmarks of the foundation of a clear, clean and simple web framework. Its just a question of 'completing' it now.

------- said...

Good post, and yes, JAX-RS seems pretty significant to anyone involved in web/REST development. We've included JAX-RS support in Kauri as well, though we also support Groovy-configured explicit routing, so that you're routing info (or URI endpoints) don't end up dispersed across your code. Here's an axample: http://www.kauriproject.org/trac/browser/trunk/samples/kauri-routing-sample/src/main/kauri/router.groovy

Peter Thomas said...

A few comments:

helping the application programmer focus on returning DTOs

This would indeed be fine for simple CRUD screens but what if there is significant business logic. Doesn't this mean that you need to process JSON (or XML) and end up working in Javascript more?

Also in my experience, the typical UI involves stuff that can't be easily categorized as "server side logic" - for e.g. showing / hiding controls / sections of the page depending on data. This code has to go somewhere.

@Jon (comment # 4):
Take a look at the example hotel room booking application. Implementing something like that with any other framework (specifically the 'conversations' context) has never been done before quite like it.

I'm not so sure about that, please see this
implementation of the hotel booking example in Wicket.

That reminds me, the typical web-app does need to manage state and you need to handle this somehow if using REST. Don't get me wrong, I appreciate REST for e.g. data transfer (POX / JSON) but I do feel it may be more trouble than it is worth for rich web-applications. REST does makes sense if you really have the need to support multiple clients at the same time (Flex / PHP / etc).

Also I have to mention some things to consider when choosing GWT.

Staff Software Engineer at Google said...

@James, the issue of "if-modified checks with etags and the like" is a cross-cutting concern that we've thought about a lot.

We do have a client-side interceptor implementation, but we don't have a RESTful cache implementation yet.

How would you handle etags and the like with the Jersey API?

James Strachan said...

Peter


helping the application programmer focus on returning DTOs

This would indeed be fine for simple CRUD screens but what if there is significant business logic. Doesn't this mean that you need to process JSON (or XML) and end up working in Javascript more?


Well it depends on your application. You might have a very complex bit of logic exposed as a REST service; which - say - a rich client or Excel or ruby or whatever does all the work client side then posts the completed DTO.

You only have to expose RESTfully resources you want - I'm not necessarily saying everything you ever build in a web application will be both HTML enabled and XML/JSON enabled.



Also in my experience, the typical UI involves stuff that can't be easily categorized as "server side logic" - for e.g. showing / hiding controls / sections of the page depending on data. This code has to go somewhere.


It depends what kind of UI you are building. Is it inside Microsoft Office or .Net - in a rich client or a web browser etc. Either way you can do show/hide of parts of a page either on the server side or client side; its up to you.

James Strachan said...

sduskis - not totally sure yet, was kinda thinking out loud :)

I wonder if we need some way to be able to kinda generate an ETag more generically from an entity? e.g. annotating a couple of fields to denote the things the framework should use to generate an ETag that the client side or server side could use?

Peter Thomas said...

I'm not necessarily saying everything you ever build in a web application will be both HTML enabled and XML/JSON enabled.

Huh, I thought the title of this blog post was "the one Java web framework to rule them all? ;)

But agreed, my point is you typically can't get away with having only annotations and "lightweight" controllers on the server and implementing view-related logic, state handling and security on the client is non-trivial.

James Strachan said...

Controllers in JAX-RS don't have to be lightweight; they can be heavy and complex if you wish (working with EJBs or BPEL or whatever you like). Inject whatever you need in your controllers to do whatever you want to do.

While implementing complex rich clients on the client side is non trivial, its not exactly rocket science either - and complex applications are not trivial anyway - wherever you put the logic :)

Peter Thomas said...

Okay, okay, just that you said in your post that you were focussing on web frameworks that spend most of their time rendering HTML / XML / JSON and not building complex server side UI stuff. You commented above that "heavy and complex" server stuff is ok - well now you can take your flame-retardant suit off ;)

I've done a fair amount of UI work in Javascript and while it indeed isn't rocket science - it certainly isn't something I would recommend if you have the option of using Java instead.

a said...

@Peter: Thank you so much for doing the analysis. One thing you don't address in your posting is whether or not your application is 100% functionally complete to the Seam version.

While memory and cpu usage is important, it is honestly not a concern of mine. Disk is cheap and servers are cheap... I run on 16gig 8core dell 2950's. What is more important is whether or not the application is easy to code and is functionally complete.

Additionally, I'm just not a fan of Wicket compared with Seam. Annotations, ejb3 beans/entities, jboss, etc. is definitely the way to go when it comes to creating large scale enterprise 3tier applications. I wish jsr299 was done already. =)

James Strachan said...

Peter - I confess to really liking GWT as a solution for complex rich web applications to avoid too much JavaScript and to promote reuse of code across Java client and server; all the complex UI resides on the client and relatively simple RESTful services on the server.

Ivan said...

A few practical questions:
What if you webapp has a bunch of files that are uploaded and need to be available as static entities (yet protected by some authentication mechanism eventually).

and

Doesn't url mapping have a natural grokking limit? One of the best things about Php is that 1 file = 1 controller. Once you find the path (assuming no crazy rewriting) you know what is being executed easily,

and finally,

Aren't some things are easily done extracted from class definitions. Say I want to send an HTTP caching configuration over all images served from this url stub, but all other from a different url stub should have this http header etc etc etc... Something like urlrewritefilter does that great, but JAX-RS seems to say "nah, forget configuration files, just do it class by class!"

James Strachan said...

1) sounds like either WebDAV or JCR (either delegate from JAX-RS or use WebDAV/JCR directly

2) sure - its up to you how you map URI paths to classes/methods. If you want to use 1 class per path (or path segment) thats fine.

Am hoping eventually Java IDEs will be JAX-RS aware so it'll be easy to navigate from a URI to a resource bean or at least see the URI -> bean mappings.

3) this sounds like a cross cutting concern. JAX-RS focusses on implementing individual RESTful services (rather like controllers in Rails etc)

If you have cross cutting concerns you can implement them as Servlet Filters, Jersey filters or via AOP on the resource beans (depending on exactly what your concern is and at what level you want to operate).

Peter Thomas said...

Jon (4 comments above) said:

One thing you don't address in your posting is whether or not your application is 100% functionally complete to the Seam version.

@Jon: I thought I made it pretty clear that it *is*. Anyway, you can check out the source, run the demos and see for yourself.

a said...

Sorry Peter, but there is stuff missing. Search is missing. Maybe I'm missing it cause it is part of Wicket, but the whole Seam Conversation part is also missing.

Also, I have to admit, now that I've explored Wicket further, the whole one class to one html file and then describing the core contents of the html file in the class model just doesn't make sense to me. That model has been done before and it doesn't work long term. I built Jakarta ECS ages ago and that was totally the wrong model.

Please, I don't mean this to be flame bait or a Wicket vs. Seam war. I'm just expressing my personal style of preference after having worked with so many different web frameworks in so many different languages for the last 15 years.

Peter Thomas said...

Sorry Peter, but there is stuff missing. Search is missing.

Nope. See line 37.

the whole Seam Conversation part is also missing.

Nope. See line 34. Ah, I get it, after your love affair with annotations, ejb3, seam and jsr299 you were probably expecting an annotation - gotcha ;)

Also try doing bookings in multiple browser tabs, it works.

Peter Kelley said...

If you like Rails but want a Java alternative have you had a look at Grails? Grails manages to give you a Rails like experience whilst doing all the heavy lifting to integrate Hibernate, Spring and Sitemesh under the covers. AJAX and JSON rendering are easy too.

Any Java programmer should be able to pick up Groovy relatively easily as all of the class libraries are the same and you can use essentially Java syntax until you learn the Groovy shortcuts.

James Strachan said...

Thanks Yellek - yes I'm aware of Grails. BTW did you know I created the Groovy programming language that is behind Grails?

One of the interesting things is JAX-RS works great with Grails and Scala due to their support of annotations and static typing. See the groovy + scala examples in the Jersey distro.

So I'd like to see JAX-RS be the basis of the MVC layer in Grails too.

Pete said...

Hi James,

How would we handle multi-level form parameters? I've been working with Struts 2 recently, in which you can give the action class properties of a complx type such as Employee. When you create a form that holds details of an employee, you name the fields things like "employee.name", or "employee.gender", and these values are mapped by the framework onto the properties of an Employee object.

I don't see any equivalent to this in the JAS-RX spec, but maybe I'm missing something?

Cheers,

Pete

James Strachan said...

Pete: its easy to register an entity resolver capable of handing the conversion of the POST payload of whatever mime type you wish (e.g. form encoding) to whatever bean types you want.

So we could easily reuse the same Struts2 multi-level-parameter binding classes inside JAX-RS.

JAX-RS is very pluggable - its easy to plugin any adapter from any MIME types to any of your application objects using whatever technologies you wish - JAXB / XStream / Jettison or some custom bindings of your choosing.

James Strachan said...

I meant entity provider not resolver :) But you get what I mean.

Or to say what I just said in another way - it should be easy to reuse all the good stuff from Struts2 from within JAX-RS

Alexandru Craciun said...

Hi James,

I’m using Stripes for some time now and I’d like to switch to a JAX-RS implementation (I may go with RESTeasy of Jboss). And I asked myself the same question as you: what’s left for a Web framework after that? Since it’s almost a year now you posted this article, did you get more experience with that? In my opinion, I’d miss the Stripes’ layouts and the validation part (that we linked directly to the jquery validation plugin).

Unknown said...

I've heard of a JAX-RS combination with GWT. But I cannot say anything about it. I think there are many developers who would like to have a JAX-RS web gui framework.

See:
State of the art Java web framework for RESTful GUI apps?

James Strachan said...

Agreed. The missing piece seems to be easily integrating JAX-RS on the server side with a GWT client side (which should work on any RESTful endpoint).

A friend and colleague of mine has created this which looks interesting...

http://hiramchirino.com/blog/2009/10/restygwt-a-better-gwt-rpc/