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
Saturday, February 7, 2009
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):
Example: JSR-311
To explain the issue, here is an example from the Jersey documentation (JSR-311):
@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.
Lets look at another example to drive this problem home. Suppose I was going to develop a class which does the following:
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:
Remember: Annotations are not the solution to configuration.
Update 2: Removed EJB3/JPA Example. Thanks Nuno.
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):
- Restlet
- Jersey (JSR-311)
- Spring-MVC 3.0M1
Example: JSR-311
To explain the issue, here is an example from the Jersey documentation (JSR-311):
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).
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 }
@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.
- JAX-WS (JSR-224) @WebService annotation
- Spring-MVC @RequestMapping annotation
- Others which escape me at the moment
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
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?
Remember: Annotations are not the solution to configuration.
Update 2: Removed EJB3/JPA Example. Thanks Nuno.
Subscribe to:
Posts (Atom)