Shoehorning Java into RESTful Design
No one can deny the positive impact Java has had on the software development landscape over the years or that it and the JVM remain the dominant general solution for many developers and applications. Whether it's been CORBA, Java EE, SOA, REST or Web Services, Java has been able to support them all. Given the ubiquity of Java and REST, it was only a matter of time before a standards based approach to merging the two would appear and that was JAX-RS, which was introduced in EE6. There are many JAX-RS implementations, including Jersey (the reference implementation) and RESTeasy, which are used widely.
Over the years there has been criticism about JAX-RS though, particularly around whether or not it encourages RESTful design. Some of these issues were taken up by the JAX-RS 2.0 technical committee, but as recently as JavaOne 2012 there were still questions around the standard. Earlier this month, Zapthink entered the discussion with an article that once again questions whether Java or even JAX-RS is appropriate for building RESTful applications.
The ongoing efforts of the Java Community Process (JCP) have augmented the capabilities of the Java ecosystem in order to tackle a wide range of new problems and situations. This ongoing work on Java may continue to meet your needs for years into the future. But then again, maybe not. The heavyweight model-view-controller (MVC) architecture of Java EE, or simply the object-oriented context of Java more broadly may not support alternative architectural approaches.
Unfortunately, JAX-RS is a classic example of shoehorning. It adds some RESTful capabilities to Java, but fights the RESTful architectural style every step of the way. Case in point: the Hypermedia as the Engine of Application State (HATEOAS) constraint. JAX-RS 1.1 didn’t support hypermedia at all, which essentially meant that we would have to simulate HATEOAS characteristics by utilizing core Java capabilities. To make JAX-RS fully RESTful, you would have to design applications that satisfied all of REST’s architecture constraints, compensating for those features that did not have adequate support during development. JAX-RS 1.1 provides adequate support for satisfying some REST architecture constraints, but punts on HATEOAS.
This lack of hypermedia support was something that the JAX-RS technical committee have tried to address in the latest version, but it has not gone far enough as far as the article is concerned: JAX-RS uses Java annotations heavily but there are no annotations to express hyperlinks, leading to ad hoc approaches when they should be part of the standard. According to the article, there are also other areas where even the new version of the standard fails to deliver, although it is arguable whether or not these belong within JAX-RS or in some other standard:
It’s also important to standardize custom media types whenever possible, and you must also select which standard media types and custom media types you should use. Furthermore, the Service discoverability design principle requires having hypermedia controls in place, based on the REST HATEOAS design constraint. Discoverability provides a way of making the protocol self-documenting.
Finally there is one significant constraint imposed on JAX-RS that Zapthink believes prevents it and Java from being appropriate for RESTful services. As Arun Gupta explained when discussing the early draft of JAX-RS 2.0, there are two types of links within hypermedia:
Linking resources together is one of the main RESTful principles. There are structural links that are used to avoid sending a complete representation of a resource and enable lazy loading. The clients can follow these type of links to retrieve the "pieces" they need. A transitional link is used to update the state of a resource and is typically identified by a "rel" attribute. Structural links are normally in the entity; transitional links could be in link headers or the entity.
However, despite the fact that JAX-RS 2.0 only supports transitional links, Zapthink believes neither are strictly necessary for RESTful services:
If we simply take a Java object and convert it into hypermedia, we end up with links that represent all the various method calls on the associated object instances, resulting in excessively large, complex representations. Instead, JAX-RS encourages transitional links which enable the client to drill down to the underlying aggregate data. But if we weren’t handcuffed by the Java object structure in the first place, we’d never bother with transitional and structural links. Instead, we’d design our hypermedia applications to support discoverability. In other words, a core Java pattern becomes a hypermedia antipattern.
Apart from the fact that JAX-RS 2.0 may still be deficient for building RESTful services, the author's conclusion is that you need to remember that REST is not an implementation but an architectural approach:
People are often confused while developing with JAX-RS and thinking REST. JAX-RS is not REST design; rather, JAX-RS should support good RESTful design. Furthermore, the use of JAX-RS API does not lead to the creation of fully RESTful Services unless you have completed proper RESTful design beforehand. The design has to ensure that you have satisfied all RESTful architecture constraints.
Of course this is something that others have said before in relation to REST or SOA. But are there some fundamental problems with JAX-RS or Java for building RESTful services as the Zapthink article describes? One of the commenters on the article asks:
In all seriousness, what language would you suggest as a replacement for Java when building systems with a RESTful approach? I understand that Java is getting “long in the tooth,” but I firmly believe in the benefits of strong typing and other programming practices that Java embodies. Would you consider Scala (the next logical evolution of Java) more suitable? If not Scala either, then what would you suggest?
And the author responds:
I don’t favor any one language over another here simply because I firmly believe that any programming language can be advantageous as long as it provides adequate support for implementing REST compliant architecture. Of course, architecture will have certain influence of the language of choice. But more important here is focusing on designing application to conform to REST design constraints.
Which still leaves the question: is Java being shoehorned in to RESTful design, and particularly any more than other languages?
JEE is the larger issue
Oracle needs to take a page out of the eclipse ecosystem playbook and release a plugin based JEE spec. The core JEE should just be a spec for how to write standard extensions and then let each part of the JEE spec evolve on its own release cycle; this will make it possible for different users of Java to customize jee solutions to fit their needs.
The one size fits all approach implicit in the JEE release cycle no longer works because the world is just too complex for one size fits all approach.
With the rise of the cloud and virtualized operating system instances it makes a lot more sense to embed an application server in app than to deploy an app onto application server. Creating an embedded app server out of standard plugins will lead to more optimal solutions and give the Java ecosystem the ability to provide standard solutions to emerging problems quickly.
It will also allow failed approaches and api/frameworks to just die and be ignored without having to support them for years and years as part of the monolithic spec.
When we classify ReST as Hypermedia, most fail.
Jersey, CXF, Restlet, Play!, RestEasy, Spring MVC, Spring HATEOAS, Apache Wink, Grails, Spray, Lift, Compojure, Moustache.
Clearly, there's no shortage of tools!
A few, notably Jersey, CXF, RestEasy and RESTEasy are active on JAXRS 2.0. As a developer, I can definitely see high advantage towards the upgrade, but it isn't about HATEOAS or Hypermedia. It is about accessibility of the client framework, async goodies, and filtering that I'm interested in.
Ruby programmers using sinatra, python guys with WSGI derivatives, node folks via restify/express, api designers using swagger, etc. don't get much hypermedia love out of the box, either! Somehow, and despite the HATEOAS concept being 12 years old, there's still very little support in the industry (web browser excluded).
What we all get are tools to make design, routing and transformation of RESTful apis easier... or at least the "level 2" (de-facto) REST.
For those looking for hypermedia, don't despair. Folks already do this.. even with jax-rs. One more dogmatic HATEOAS api I've seen is vCloud, implemented with jax-rs and servicemix (both java) if you trust log output:
The point isn't to endorse the absence of HATEOAS in JAXRS 2.0. Rather, I hope I've highlighted that it ain't just java, and it ain't just the JVM who aren't gung-ho or caught-up with HATEOAS, yet.
If you are interested in HATEOAS in any platform, participate in groups like api-craft and/or pressure spec leads with your use cases. If you are really bold.. make a design for truly HATEOASsian java or JAX-RS spec, and throw it up on github! No-one's stopping you, and I would love to read it.
JAX-RS is just right
JAX-RS is just about right. It's (IMHO) a brilliant software design given the packages it is meant to work with (Servlets/JavaEE). With EE it really shines.
The hypermedia constraint issue is something that matters at a totally different layer. There is no direct support for the other constraints either. It's left to the API designer.
Personally I am grateful that we do not yet see hypermedia support because the research how that should work has not even started. better have nothing than have a framework leaking bad approaches.
From a RESTfulness POV I'd vote for dropping JAXB MBRs and MBWs from JAX-RS because they almost inevitably lead to unRESTful design.
What is really missing from JAX-RS is support for non-blocking request body reading and response writing but that is not JAX-RS's fault. (Jersey, BTW, is working on that internally by taking the concept of the new AsynResponse class a bit further).
general-purpose programming languages and purpose-built frameworks
RESTful design has it's own rules and the excellent and elegant JAX-RS framework makes it easy to adhere to those rules by implementing direct support for most of REST's concepts, on top of the general-purpose facilities of the Java language (classes, annotations, etc.). Similarly, JDBC and JPA provide two very different approaches to playing by the rules of a relational database from a Java program.
Yet, perfectly usable HTTP-based services can be written with JAX-RS that wilfully (or by negligence) ignore some of REST's principles - maybe they make effective use of HTTP verbs but shun HATEOS. Just like JDBC and JPA can be used to implement persistence in a relational database that violates some of the normal forms.
This liberalism in how to use JAX-RS to implement services is perfectly welcome for several reasons, but most fundamentally because it gives choice, enables creativity and allows elegant solutions to be built that chose from the REST principles the ones that are beneficial to the concrete situation at hand. There are still design decisions to be made. Just like violating the 3rd normal form in a database schema may be a perfectly legitimate thing to do.
Would a Scala-framework for RESTful services look different from JAX-RS? Well, the features available to a framework designer are much richer in Scala than in Java, and Scala developers have a quite distinct approach to framework design, so it's no wonder that, for instance, Bowler looks very different from JAX-RS (personally i prefer the latter). Just like ScalaQuery is quite a different beast than JDBC. One can argue about elegance, type-safety, and other aspects of these frameworks, but from ZapThink's viewpoint they would presumably all fare badly, because they are all much more than REST-oriented languages and consequently allow - just imagine! - non-dogmatic solutions to be built.
Todd Montgomery Dec 19, 2014