01 May 2012

Deconstructing Spring myths

Over the past five years, I have had the pleasure of working on different Java enterprise projects based on OSGi, Java EE and Spring. Among these three platforms, Spring is the one I'm least happy with.

Granted, Spring lets you build complex enterprise applications without too much pain, or else it wouldn't be so popular. In the times of J2EE 1.4, Spring must have felt like a breath of fresh air, and without the competition of Spring and Hibernate, J2EE might not have evolved into what Java EE 6 is today.

But somehow the glory of Spring's founding myth of killing the beast that was J2EE seems to be fading. The former beast is now as manageable and easy to use as Spring ever was, or even more so. Dependency Injection in Java is no longer synonymous with Spring (and in fact never was).

The Spring Framework needs a new raison d'ĂȘtre, and the current strategy seems to be diversification: Projects like Spring Data or Spring Social offer new features that have no equivalent in Java EE or OSGi. And of course, any Spring XYZ project requires the Spring Framework. But looking at the capabilities of the Spring Framework itself, where are the killer features?

Does Spring provide solutions that are smarter or easier to use than equivalent constructs in Java EE?

Here is a list of reasons why I feel more productive on Java EE 6 than on Spring 3.1.

There is no Spring without Java EE


Most debates about Java EE vs Spring sound like an either-or question, but this is a misconception. You can build an application on Java EE without ever using a Spring API, but you can't really build an enterprise application on Spring without using a number of Java EE APIs and implementations.

A typical Spring-based application includes

  • a web container, usually Tomcat, which means Servlet, JSP, EL, all of which is Java EE
  • a service layer, which has the highest chance of being Spring-only, with Spring transactions and Spring dependency injection
  • some web service endpoints, most likely JAX-RS or JAX-WS, which means Java EE again
  • a persistence layer, traditionally Hibernate Native API + Spring templates, but these days there's really no reason for preferring vendor-specific APIs over JPA 2.0
  • some messaging, e.g. with ActiveMQ, which means JMS and thus Java EE again.

Thus, Spring and Java EE applications mostly differ in the following areas only:
  • the web framework (Spring MVC vs. JSF vs. Wicket vs. Vaadin vs. Struts vs.....)
  • Spring Beans vs. EJB
  • Spring Dependency Injection vs. CDI or Java EE 5 @EJB or @Resource injection

In the age of AJAX and component-oriented web frameworks, Spring MVC feels rather old-school. JSF 2.1 has a lot more to offer, and if you prefer an independent web framework like Vaadin, the underlying container does not matter anyway.

Who's afraid of EJBs? All you need is a @Stateless annotation on your Java class, and you get a thread-safe service where all public methods are transactional by default, which is just what you need in most cases.

And finally, CDI is much more powerful that Spring Dependency Injection, due to its seamless scope handling, its event model and its portable extension mechanism.

API vs. Implementation


Spring has no clear separation of API and implementation, neither at specification level nor at code level. The Spring Reference Manual documents the one and only Spring Framework implementation. The Spring Javadocs document each and every class contained in the Spring Framework. It is not easy to distinguish API level classes from container internal classes.

By contrast, Java EE is first and foremost a set of specifications, represented by a collection of thin API JARs or an all-in-one javaee-api.jar. There are different independent implementations by different providers. Provider specific implementation classes are not normally visible to the user.

Vendor Lock-In


Competition is a good thing. When you are having an issue with your application running on a given Java EE server, try another server. This will give you some insight whether or not the issue is caused by your application or the server.

With Spring, there's only Spring. You can't swap framework components. You can't even cherry-pick framework components. There is insufficient separation of concerns. Inherently, there is no reason why a web framework or a NoSQL persistence provider should have to be tied to a given dependency injection container. But you can't use Spring MVC or Spring Data without Spring Core, just like you can't run Microsoft SQL Server without Microsoft Windows.

JAR Hell


Java EE means one-stop shopping for the core functionality of an enterprise software stack. javaee-api.jar provides the interfaces you need to start developing your own applications. All the required runtime environment is provided by the application server.

Yes, the application server runtime does contain a lot of stuff you'll never need. But modern servers like GlassFish 3.x or JBoss AS7 are modular and lazily activate only the stuff you do need, so there is no runtime overhead. And even a monolithic server like Resin 4.x has a surprisingly small footprint.

My current project is a Spring web application deployed on Tomcat. The final WAR has more than 100 JARs in WEB-INF/lib. More than 30 of these JARs are due to Spring itself, its dependencies or other Java EE components not provided by Tomcat.

In other words, by moving from Spring to Java EE, I could drop a third of the dependencies of my application. And I'm not talking about saving 30 megabytes of disk space, but about the effort of maintaining these dependencies and resolving version conflicts of transitive dependencies.

Configuration Hell


The flip side of JAR hell is configuration hell. With Spring, once you have gathered all required components, you also need to configure them. You may get away with an automatic component scan for your own application beans, but there is always a certain amount of manual plumbing for setting up framework beans, and standard features like transaction management or property substitution have to be enabled explicitly.

Most Spring-based projects started before 2010 still use XML configuration which for my taste is hard to read, extremely verbose and hard to refactor. Spring 3.0 first introduced Java configuration as an alternative but left it unfinished. Spring 3.1 finally supports type-safe Java-only configurations. Unfortunately, the reference manual and Spring extensions like Spring Security still promote XML configuration and leave it to the user to figure out the Java equivalents, which can be rather challenging, especially when custom Spring XML namespaces are involved.

With Java EE 6, little or no configuration is required. Transaction management works out of the box. Use an empty beans.xml marker file to enable CDI. Define the data sources and connections pools for your application in your application server's administration console. That's it.

Thread Safety


Spring leaves thread safety up to you. Controllers and services have singleton scope by default, so you can't use instance variables, or you need to protect them explicitly.

With Java EE, stateless EJB are pooled, concurrent requests each get served by a new beans from the pool, so your beans are thread-safe by default, unless you modify static members or global singletons.

Singleton Antipattern


The fact that Spring beans are singletons and not thread-safe by default tends to promote a rather ugly procedural programming style. Suppose you have a service with one public method performing some non-trivial business logic, factored out into a number of private methods.

In a stateless EJB, your private methods can share state in member variables within the same request (i.e. public method call), so in fact, the EJB is not quite as stateless as it may appear.

In a Spring bean, you often see private methods with long parameters lists, since you cannot share state in member variables, so you have to pass it around in method arguments.

Mixing Scopes


Due to these issues with singleton Spring beans, you may want to use the prototype scope, or the request scope in web applications.

Now when you inject a protoype or request scope bean into a singleton bean, Spring does not by default do the right thing to ensure that the injected bean is indeed a different instance per request. You need to resort to method injection or configure a scoped proxy explicitly.

CDI, on other hand, automatically proxies injected beans when needed.

Transactions


Spring itself does not provide global transactions across multiple resources. It can delegate to a JTA transaction manager but does not provide its own implementation.

Working with two or more persistence units in the same application, you need to configure a transaction manager per persistence unit and reference the correct instance in the @Transactional annotation of your service class or method.

In Java EE, transactions are managed by the container by default. EJBs are transactional by default. The container can handle multiple persistence units without further configuration. Global transactions spanning multiple datasources work out of the box if you configure XA datasources.

Load Time Weaving


Some persistence providers require load time weaving, also known as byte code enhancement. The JPA specification defines a hook for this purpose in PersistenceUnitInfo.addTransformer().

With OpenJPA and GlassFish, this works like a charm. Using OpenJPA with Spring and Tomcat, the required set-up is rather a nightmare, so I ended up using build-time enhancement, which is a lot easier to configure, but still requires additional manual configuration.


Summary


Spring has had its merits in giving relief to frustrated J2EE developers. But this is 2012 - compared to Spring, Java EE 6 now provides equivalent or better solutions for most standard tasks in enterprise application development.

Both Java EE and Spring are far from perfect. All in all, Java EE is more integrated and easier to use - not by orders of magnitude, but noticeably so.

And none of this is an eternal truth, tables may turn again within a few years.


29 April 2012

Metamodel classes for OpenJPA with Maven, Eclipse and m2e

Metamodel classes are a not-so-well known feature of the JPA 2.0 standard. They allow you to write typesafe criteria queries using metamodel attributes instead of plain old strings to reference entity fields. (See this tutorial for some more background.)

Metamodel classes are generated by an annotation processor during the build process, but this is not enabled by default. OpenJPA logs a runtime warning when you build a criteria query and the metamodel classes cannot be found. So even if you don't use the metamodel, you may want to generate it just to get rid of this warning.

This article explains how to generate the metamodel both in Maven batch builds and in the Eclipse workspace.

15 April 2012

Multi-Instance Deployment from Eclipse to Tomcat

Problem

  • You are developing a web application for Tomcat in Eclipse.
  • You want to deploy multiple instances of the same application with different configurations directly from your workspace.
  • Of course, you don't want to duplicate any projects in your workspace.

Solution


This scenario can be solved quite easily with the vanilla Apache Tomcat adapter of Eclipse WTP. There is no need for any additional Eclipse plugins.

25 January 2012

Integration Testing for JBoss AS7, Tomcat and Weld SE

Initially, the jeeunit Integration Testing framework was exclusively focused on Java EE 6, supporting GlassFish 3.x, which was the only Java EE 6 compliant server at that time. Support for Resin 4.x has been added in subsequent releases.

With the current release 0.9.1, jeeunit supports JBoss AS 7, as well as alternative containers and injection methods beyond the scope of Java EE 6. You can now run jeeunit tests on Tomcat 6 and 7 and Weld SE containers.

Tomcat can be combined either with Spring 3.1 or with CDI (Weld Servlet) to inject dependencies into jeeunit tests.

And there's more to come: While jeeunit will continue a life of its own for a while, I'm planning to merge it step by step into Pax Exam, the OSGi testing framework of the OPS4J community.

Pax Exam and jeeunit both implement an in-container testing approach - while Pax Exam focuses on OSGi alone, jeeunit now supports various other containers, but no OSGi at all.

The Pax Exam/jeeunit merger opens interesting perspectives for hybrid applications, i.e. enterprise applications composed of traditional WARs and OSGi bundles. GlassFish 3.x supports this hybrid application model, implementing a subset of the OSGi Enterprise specifications.

For Pax Exam, the road towards the next major release 3.0.0 will be marked by a sequence of milestone releases, each of which is to incoporate a new container adapted from jeeunit.

A Pax Exam GlassFish Test Container is the goal of the first proof-of-concept milestone 3.0.0.M1. This is work in progress on a dedicated branch exam3-milestones in the Pax Exam GitHub repository.

Stay tuned...

03 January 2012

Troubleshooting VisualVM Remote Connections

I was trying to use VisualVM to monitor the memory usage of a build job on our build server. According to the documentation, this should require nothing but a jstatd daemon running on the remote machine.

For some reason, I could not see any remote applications in my local VisualVM. It was not a port issue, all the required ports were reachable via telnet.

Googling around, this article finally gave my the important clue: Our network does not have consistent DNS names, so I had to connect to the remote machine via IP address. Setting the java.rmi.server.hostname property for jstatd to the IP address solved the problem.

Summary


On the remote machine

Create policy file for jstatd

grant codebase "file:${java.home}/../lib/tools.jar" {
    permission java.security.AllPermission;
};

Start jstatd with this hostname file and the IP address as hostname

jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.0.123

On the local machine

Start jvisualvm and add a Remote Host with the given IP address. A jstatd connection will be established by default. You should now see your remote applications.

21 December 2011

Spring Integration Tests with Real Transactions

Spring's Test Context has a @Transactional annotation for wrapping tests in a transaction started and rolled back by the test container, to keep the tests from modifying the database. This is just what you need for deterministic, repeatable database tests.

On the other hand, due to this approach, the transaction boundaries in your test system differ from the ones in your production system, which can lead to errors in production which were never noticed in your tests suites.

I wouldn't go as far as saying that transactional tests should be considered harmful, but at least you should be aware of the side effects which may or may not be harmless in your specific use case.

For tests with real transactions, you need to take care of cleaning up the database yourself.

JUnit rules are a neat way of doing this. Here is an example:

02 December 2011

XVisitor: Visitor Pattern for JAXB

XVisitor is a plugin for the xjc code generator to enrich the JAXB model generated from an XML schema so that users can work with the Visitor pattern on this model.

16 November 2011

Eclipse Performance on KDE and Ubuntu 11.10

If you suffer from poor graphics performance when using Eclipse under KDE, especially when scrolling large trees, check your GTK+ Style.

After changing the style from oxygen-gtk to QtCurve, my Eclipse is now running on steroids.

I'm using Eclipse Indigo 3.7.1 on Kubuntu 11.10 amd64 with Oracle JDK 1.6.0_26 and an NVIDIA GeForce 8400 GS graphics adapter. I never used to have any issues on Kubuntu 10.04 LTS which is still running smoothly on another partition of my disk.

I had suspected the NVIDIA drivers, tried different JREs (including 32 bit versions) and Eclipse releases, none of which made a difference.

Finally, changing various configuration options by trial and error, I found out that oxygen-gtk seemed to be the cause.

To optimize your installation, install the qtcurve package, and select it in K Menu | System Settings | Appearance | GTK+ Appearance | Widget Style. Then restart Eclipse and enjoy.

23 October 2011

JBoss AS 7: Catching up with Java EE 6



In my Java EE 6 server comparison of June 2011, JBoss AS 6.0.0 was not exactly the shining star, both in terms of performance and usability.

The next major release JBoss AS 7, claiming to be lightning fast, was published in July 2011, followed by two maintenance updates in August and September.

Time to take another look at JBoss and check if it now compares more favourably to other servers.

29 August 2011

Eclipse Maven Integration Extensions

For me, the most important new feature in Eclipse 3.7.0 (Indigo) is the improved Maven Integration, formerly developed by Sonatype under the name of m2eclipse, now an official Eclipse subproject under the name of m2e.

m2eclipse and Eclipse sometimes used to have different opinions on what was going on in the workspace, and so we had to go through series of refresh/update dependencies/update configuration/rebuild voodoo (or "m2eclipse dance" as some called it) to get projects in a good state. (Quote from the m2e Wiki).

m2e has a different approach. First of all, it complains when detecting a Maven plugin in one of your POMs that it cannot handle out of the box. m2e flags your POM with an error marker that will not go away until you tell m2e what do to about the unknown plugin. The easy way out is a Quick Fix to ignore the plugin, which means you'll have to run the corresponding Maven goal manually when you need it.

However, when the Maven plugin in question generates source code or post-processes byte code, this is usually not sufficient - ideally, Eclipse and m2e should pick up the required build steps from your POM automatically.

This issue is addressed by m2e extensions, which provide the missing link between Eclipse project builders and Maven plugins. An m2e extension for a given Maven plugin not only invokes the required mojos but also informs Eclipse about new source or binary folders created by the mojos, so that Eclipse and Maven can stay in sync.

My projects use a number of Maven plugins that are not supported by m2e out of the box, e.g. for JAXB and OpenJPA, so I started creating some custom extensions for these plugins, based on a GitHub fork of the official m2e extensions from Sonatype.

See the wiki page at GitHub for more details. The GitHub project also contains an Eclipse update site (aka p2 repository) for installing the plugins. Time permitting, I'll try to make these extensions available via the Eclipse marketplace.

For any fixes, additions or new extensions, feel free to send my pull requests.