A couple weeks ago I discovered the Ninja web framework
via a link on Twitter. It's presented as a Java web framework largely inspired from
the Play! framework. What I liked from the very beginning
is that it's a Java citizen before all: plays nice with Maven and everything you're used
to do with/in a Java project. This is in total opposition to Play! which forces you to
use its own tools and way of thinking. Furthermore, Play! (v1) does runtime bytecode
manipulation to override the semantics of static
fields (replacing them with a
ThreadLocal
). This is probably the one thing that I dislike the most in Play!: it's no
longer Java.
Ninja web framework: Play! framework done right?
— Thomas Broyer (@tbroyer) April 5, 2013
Looks a lot like JAX-RS though; I think I'll stick with that one.
ninjaframework.org/introduction.h…
I like Ninja's minimalism but I think it can do better (and I'm not even talking about the rather limit set of features compared to Play!). For example, Play! is advertized as being highly scalable, partly due to using non-blocking I/O and more specifically Netty. Ninja also talks about Netty being a potential deployment target, but had a strong dependency on the Servlets API. A few hours of hacking later, Servlets are only an implementation detail.
I'm looking at OAuth 2.0 for that project at work where we'll use Play! (v2) so I wondered
how it'd look like in Ninja, and I found out there's no clean way to communicate between a
ninja.Filter
and a controller. So I proposed adding
getAttribute
and setAttribute
(it turns out that Play! already has those methods).
Digging deeper in Ninja's internals, I found a couple other things I'd like to change, and I started working on them, along with Grizzly and Netty backends. Raphael A. Bauer is very open and very reactive, so overall working on Ninja was a pleasure.
But there was still something that bugged me, and I couln't put words on it at the time.
The more I look at frameworks like Play or Ninja, the more I want to go “no framework”. Will have to experiment with that…
— Thomas Broyer (@tbroyer) April 7, 2013
Don't get me wrong: I'm not saying Play or Ninja are bad; just that, 1 or 2 days in, I really can't say I'm in love.
— Thomas Broyer (@tbroyer) April 7, 2013
Overall, I think it boils done to the fact that I don't like frameworks. I largely prefer libraries. Play! is a full-stack framework, and Ninja borrows from it by providing the router, the templating engine (Freemarker), a simple API to send mails, etc.
JAX-RS 2.0
At work, I'm also working concurrently on a project using JAX-RS 2.0 and I really like it. JAX-RS provides its own dependency injection mechanism but we made it play nicely with Guice (and I even experimented with replacing Guice with Dagger). It feels a bit weird to have two DI framework (Jersey comes with its own DI framework called HK2) coexisting in the same app but Jersey is only one implementation of JAX-RS (just like Guice and Dagger are implementation of JSR 330, except JSR 330 doesn't deal with how you configure injection).
Hacking on Ninja+Grizzly the other day, it happened to me that I actually want it to be more like JAX-RX. The main differences between them would be:
- Ninja's controllers are much simpler than JAX-RS resource classes and methods, but also less flexible.
- The mapping of URLs to controllers is centralized in
conf.Routes
in Ninja, where as in JAX-RS it's scattered around all the resources as annotations are put on classes and methods. JAX-RS is slightly more type-safe though: you don't have to use a method's name (as ajava.lang.String
, error-prone, easily broken by refactorings) when defining your routes, only possibly when creating links to resources (it depends how you built your resources). - JAX-RS doesn't come with a template engine, but it's really easy to make one. The big advantage is that you're free to choose the engine you want. On the other hand, choosing the template dynamically requires a bit more work.
- JAX-RS doesn't come with support for file upload, but again it's easy to build, and both Jersey and RESTEasy provide it as an extension (you're then building a Jersey or RESTEasy app though, not a JAX-RS one).
- JAX-RS won't map your
application/x-www-form-urlencoded
request body to an object, but yet again… (you know what I'll say?) it's easy to build if you really need it. And JAX-RS can also do it differently: if your problem is having too many arguments to your resource method, JAX-RS will inject fields, contrary to Ninja (because resource classes are short-lived in JAX-RS, when they're generally singletons in Ninja, so there's no shared state unless you specifically build for it). - Ninja builds on Guice, whereas JAX-RS has it's own DI framework (but can also work with CDI or whatever, then again your app just becomes less portable, which can or cannot be a problem)
Overall, I prefer JAX-RS as it allows you to compose the parts you want (template engine, etc.) as you want, at a somewhat negligible cost (compared to the flexibility it brings!)
Servlets 3.1
Approximately at the same moment, I see something about Servlets 3.1 so I go check the spec to see what's new. I end up reading the spec almost back to back, and I generally like what I see. The one advantage compared to Ninja and JAX-RS is that it has support for NIO (already implemented in Grizzly 3.0-SNAPSHOT, among others), but it's lacking advanced routing (with extraction of path-parameters from the URL, and construction of links from a URL-Template/pattern) and I don't know of any such thing as a standalone library.
Lightweight web “framework” (toolkit?): Servlet 3.1 + some router + DI container + template engine. The problem is to find a router…
— Thomas Broyer (@tbroyer) April 8, 2013
I unfortunately haven't had the time yet to do the experiment. I'm not even sure a full-blown router component is really needed after all (it really depends how you want your URLs to look like).
Conclusion
I haven't given much time to Ninja but in the end I think I much prefer JAX-RS 2.0.
Servlets 3.1 look very interesting but are even lower-level. Depending on your needs, I think it can be a better choice. It's lightweight enough that it can be implemented on top of many lower-level APIs (Netty, Grizzly, Jetty, etc.) so it provides a lightweight portable API (but JAX-RS is similar).
The only missing bit to JAX-RS (and Ninja) compared to Servlets 3.1 (and Play! v2) is the support for NIO. It's apparently on the radar but will go through experiments with proprietary (Jersey vs. RESTEasy vs. …) APIs. Now it hasn't really been an issue 'til now and it won't be an issue in practice for many of us (many templating engines and other renderers/serializers don't make use of NIO to begin with), but still.
So what?
Oh, this was all just musings on web frameworks from my past 2 weeks with them. I didn't talk about Play! as I haven't yet spent much time on it (I focused on SBT for now, which I must say I really don't like) nor that experiment (running in production for a couple years though) from Tim Boudreau:
Interesting new Java web framework by @kablosna; actor pattern, based on Netty and Guice.timboudreau.com/blog/Acteur/re…
— Thomas Broyer (@tbroyer) April 8, 2013
I've always tried to favor standard APIs anyway, by principle and to avoid lock-in, so
I'd rather stick to JAX-RS and Servlets (and JAX-RS can be implemented on top of Servlets
to be deployed everywhere servlets can, including e.g. Google AppEngine), but those other
frameworks bring interesting things.
I'll have to learn Play! (v2) at work anyway, let's see how it goes…