Saturday, February 7, 2009

Announcing REST support for Spring MVC 2.5

Recently I started researching how to create RESTful web services. I looked at JAX-RS/JSR-311 (Jersey), Restlet, and several others. All of them left a bad taste in my mouth for reasons I won't go into here.

Since I have been a long time fan of the Spring Framework and Spring MVC, I looked there too. Spring 3.0 is supposed to have "full" REST support. I looked at Spring 3.0-milestone1 and regret to say that I was not impressed. Maybe I didn't dig deep enough or maybe more REST stuff will show up between now and 3.0-final. One can always hope.

In the mean time, I decided to see how difficult it would be to add REST support to Spring MVC 2.5. It turns out it wasn't too difficult. I have started a SourceForge.net project and published an initial framework. Please check it out and let me know what you think. The documentation is a little sparse at the moment but its coming along.

Website - SourceForge.net Project

Sunday, January 18, 2009

An example of how not to use Java annotations

Lately I have been spending a lot of time reading and learning about REST. The theory (or "architectural style" as Roy would call it) is quite intriguing. I have spent the better part of the last several years implementing enterprise integration projects using SOAP web services. Learning about REST has been eye opening.

Like any good programmer, I learned a little about the theory and then wanted to get my feet wet by writing some code. I looked around at the different "frameworks" available (im a Java guy):
It was during this investigation that I discovered something terribly wrong with how people are using (or over-using) Java annotations. To be honest, i've seen this problem before (JAX-WS, etc) but ignored it because I thought it was isolated. The fact that I am seeing it again, in several more places, is disconcerting.

Example: JSR-311

To explain the issue, here is an example from the Jersey documentation (JSR-311):

1 // The Java class will be hosted at the URI path "/helloworld"
2 @Path("/helloworld")
3 public class HelloWorldResource {
4
5 // The Java method will process HTTP GET requests
6 @GET
7 // The Java method will produce content identified by the MIME Media
8 // type "text/plain"
9 @Produces("text/plain")
10 public String getClichedMessage() {
11 // Return some cliched textual content
12 return "Hello World";
13 }
14 }
Nice and simple. Without going into the nitty-gritty details of how this works, lets look at the three annotations in this code snippet (from bottom to top).

@Produces("text/plain")
This annotation describes the behavior of the getClichedMessage() method -- it returns plain text. Ok, that seems reasonable to me.

@GET
This annotation describes a mapping between the HTTP GET operation and the getClichedMessage() method. It also describes the behavior of the method. In REST, HTTP GET has very specific semantics which getClichedMessage() must obey. I'll let this slide for now.

@Path("/helloworld")
The final annotation defines a mapping from a URL (or URI) to the HelloWorldResource class. Now I am no expert on Java annotations but this seems like a bad practice to me. This is deployment-specific configuration information being compiled into a java class. Not cool.

I don't mean to pick on JSR-311 specifically. It seems that several other APIs/frameworks are starting to pull this crap.
Example: Streaming a File

Lets look at another example to drive this problem home. Suppose I was going to develop a class which does the following:
  • Takes an 'id' as input
  • Opens a file (based on the 'id')
  • Streams the contents of the file back to the user
This would be pretty trivial to model as a RESTful resource. I won't bore you with the code. Needless to say, this is both a useful and common capability whether you using REST or something else. It is also something that I would want to write once and use in many places (both within a single webapp as well as across multiple webapps). In other words, I would need to make sure that both the logic and annotations are reusable.

How not to use Java annotations:

In basic OO programming classes we are taught about decoupling, separation of concerns, and reuse (among other things). Last I checked, these were still good practices. I believe the examples above demonstrate a violation of these core OO principles.

If you are creating a new annotation or come across a framework which is asking you use an annotation in one of our classes, ask yourself these questions:
  • Does the annotation configure how to use something (as opposed to describing what it is/does)?
  • If you add the annotation to a class, can you reuse that class in different contexts?
If you answered yes to any of these questions, consider yourself on shaky ground.

Remember: Annotations are not the solution to configuration.

Update 2: Removed EJB3/JPA Example. Thanks Nuno.