Friday, June 18, 2010

Annotations and the Servlet 3 Specification


Now I'm seriously beginning to wonder about the authors of the Java Servlet 3 specification. This time, it's not their architectural wisdom (or the lack of it) regarding session state. It's about something even more basic to the Java language - the nature of annotations.

Chapter 8 deals with annotations that developers may use to mark their classes. Anything about the following strike you as crazy?

Classes annotated with @WebServlet class (sic) MUST extend the javax.servlet.http.HttpServlet class.
[...]
Classes annotated with @WebFilter MUST implement javax.servlet.Filter.

If we must extend a base class anyway, I wonder what the annotation is for. Just to avoid putting a few lines of config code into the web.xml file?

I would have thought an annotation like @WebServlet would be capable of turning any POJO into a servlet class, not just subclasses of HttpServlet! And we could have annotations like @GetMethod, @PostMethod, @PutMethod and @DeleteMethod to annotate any arbitrary methods in the class. We shouldn't have to rely on overriding the doGet(), doPost(), doPut() and doDelete() methods.

The same applies with @WebFilter. It could be used to annotate any arbitrary class, and @FilterMethod could then annotate any arbitrary method in the class.

Look at the way JSR 311 and Spring REST work.

I'm disappointed in the Servlet spec committee. If you're going to use annotations, then use them smartly.

It wouldn't be out of place here to comment on the horrific class hierarchy of the Servlet spec. It certainly shows the era from which it began, an era where interfaces were underappreciated and inheritance hierarchies featured classes themselves. Naming conventions hadn't matured yet, either.

E.g., my application's concrete class "MyServlet" must either extend abstract class "GenericServlet", which in turn partially implements interface "Servlet", or implement "Servlet" directly. This by itself isn't so bad, but go ahead a bit.

My application's concrete class "MyHttpServlet" must only extend abstract class "HttpServlet" which extends abstract class "GenericServlet", which in turn partially implements interface "Servlet". There is no interface to implement.

And why GenericServlet should also implement ServletConfig is something I don't understand. There's a HAS-A relationship between a servlet and its configuration. It's not an IS-A relationship.

HttpServlet should have been an interface extending Servlet.

The abstract class GenericServlet (that partially implements the Servlet interface) should have been called AbstractServlet instead, and there could have been a concrete convenience class called SimpleServlet or BasicServlet that extended AbstractServlet and provided a default implementation that subclasses could override.

Similarly, there should have been an abstract class called AbstractHttpServlet that partially implemented the HttpServlet interface and only provided a concrete service() method, dispatching requests to doXXX() methods that remained unimplemented. There could have been a concrete convenience class called SimpleHttpServlet or BasicHttpServlet that extended the AbstractHttpServlet class and provided a default implementation that subclasses could override.

My application's concrete classes should have had the option to implement one of the interfaces directly or to extend one of the abstract or convenience classes.

Oh well, too late now.

3 comments:

Najitaka said...

Is it time for J2EE to die? I mean we all know that Spring is the better framework for building enterprise Java web applications, why doesn't the J2EE people spend time creating conversions to Spring rather than band-aiding a bad technology. Sometimes you simply must throw out the white towel.

Bino M. said...

The whole idea of annotations is to convey **META** information to the compiler and to the reader of the code.
Annotations are not meant to intercept methods and override run time behaviour of those methods.

Consider the annotation @override. Does it do any magic? No! But it does tell the compiler that its an overriding method, which elimintaes programming errors (e.g mistyping the method name which would be an accidental over-loading instead of over-riding).

About the previous comment, Spring is a not a replacement for JEE. Spring is built on JEE. So how can we replace JEE with Spring?

Ganesh Prasad said...

Bino,

I have a slightly different view on both points.

1. I'm not denying that annotations are meta-information, but a quick look at how JSR-311 or Spring REST use annotations to turn POJOs into specialised components (without the need to define interfaces with associated mandatory methods) will tell us that a servlet class can be created the same way. It's a missed opportunity to simplify the servlet definition, that's all.

[Annotations are the Auguste Gusteau (of the movie "Ratatouille") of Java - "Anyone can cook!" Any POJO can be a servlet!]

2. I share the spirit of Najitaka's comment. Instead of Sun or the JCP classifying Java technologies into "core" and "enterprise" flavours, I believe it's better to unbundle them and let Maven (at build time) and Spring (at run-time) pull together whatever Java technologies are required for an application.

We can't pretend the split between JSE and JEE is clean, anyway. JEE (and J2EE before it) is an arbitrarily-named bundle of technologies. It's meant to represent "enterprise" capability, so why are JDBC and RMI in JSE when Javamail and JNDI are in JEE? Why is bean validation in JEE when Javabeans is in JSE?

Time to unbundle, I think.

Regards,
Ganesh