Monday, 18 March 2013

Upgrading to Spring 3.2

A few days ago I thought that it was about time to upgrade my sample code to Spring 3.2, after all it’s been around for a respectable amount of time and even has a bug fix release.

Upgrading to Spring 3.2 is very simple matter of upgrading your Maven version number and rebuilding, something like this:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>3.2.1.RELEASE</version>
</dependency>

...for every Spring dependency and then recompiling and that should just about it… except it isn't, this time there are a few gotchas.

Upgrading MVC Projects


The first thing you may find is that several of the normal MVC annotations including the @RequestMapping stop compiling and you'll get something like this in STS/eclipse:


…which appears kind of strange. The fix is to add spring-web to your pom.xml file's dependencies:

<!-- Add this as Spring 3.2.1-RELEASE update -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

…probably somewhere near:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

You may ask why this happens and I have a theory. This is just conjecture, but it seems logical that previous versions of Spring had a transient dependency between spring-webmvc and spring-web, which no longer exists and you therefore need specifically add your own spring-web dependency.

Now that's just a general error; however, in two of the captaindebug Github projects: tomcat-ssl and social STS/eclipse found a problem in the Spring context XML file. The line was:

    <annotation-driven/>

The error was:

Error occured processing '/social/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml'

…and the associate exception was:

java.lang.NoClassDefFoundError: org/springframework/web/accept/ContentNegotiationManagerFactoryBean
 at org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser.getContentNegotiationManager(AnnotationDrivenBeanDefinitionParser.java:293)
 at org.springframework.web.servlet.config.AnnotationDrivenBeanDefinitionParser.parse(AnnotationDrivenBeanDefinitionParser.java:151)
 at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73)
 at org.springframework.ide.eclipse.beans.core.internal.model.namespaces.DelegatingNamespaceHandlerResolver$ElementTrackingNamespaceHandler.parse(DelegatingNamespaceHandlerResolver.java:177)
 at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1419)
 at org.springframework.ide.eclipse.beans.core.internal.model.BeansConfig$ErrorSuppressingBeanDefinitionParserDelegate.parseCustomEleme
etc…

Like the @RequestMapping problem above, this problem was down to transient dependencies being wrong. In the case of the tomcat-ssl project the problem was caused by spring-security-web pulling in spring-web version 3.1.0-RELEASE rather than 3.2.1-RELEASE. Likewise in the social project the problem was caused by spring-social-twitter pulling in spring-web version 3.0.7 rather than 3.2.1-RELEASE

The fix, once again, is to specifically add spring-web as a dependency in your project

<!-- Add this as Spring 3.2.1-RELEASE update -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

EhCache Problems


Having got all the web projects working again, the next problem to crop up was in the ehcache sample code. This project also stopped compiling and this is because the class org.springframework.cache.ehcache.EhCacheCacheManager could not be found. The reason for this can be found in Spring's documentation. The Guys At Spring have moved EhCache support in the form of the org.springframework.cache.ehcache package from the spring-context module to spring-context-support. The reason for this seems sound, because EhCache is not a front line Spring package, it's a supporting package and therefore belongs in spring-context-support to reduce module bloat along with jcache, mail, quartz scheduling and commonj, whilst on the ui front it contains free marker, jasper reports and velocity support.

To fix this problem add the following to your pom.xml file:

<dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-context-support</artifactId>
       <version>${spring.version}</version>
</dependency> 

The Wrong Version of Java


In several projects I got the following error when running mvn clean install within the STS/eclipse environment:

org.apache.maven.surefire.util.SurefireReflectionException: java.lang.reflect.InvocationTargetException; nested exception is java.lang.reflect.InvocationTargetException: null
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Caused by: java.lang.UnsupportedClassVersionError: caching/EhCachePersonDAOTest : Unsupported major.minor version 51.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)

The reason for this is that the build process was using Java 6 rather than Java 7. Remember that these are old, existing projects originally created using Java 6 and then upgraded as and when required. The fix for this problem is to manually change the Java runtime version to Java 7 in the project's properties as shown in the image below:


CGLib is No Longer Required


This is not an obvious problem, but the Guys at Spring have removed the need to specifically include CGLib in your project. CGLib is required if you're using the @Configuration annotation. Version 2.2 is generally added to your pom.xml when you create a new project using the Spring Template Project option in the STS Dashboard as should below:

<!-- CGLIB, only required and used for @Configuration usage: could be removed in future release of Spring -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>2.2</version>
</dependency>

As the Guys at Spring say in their documentation:

In prior versions, users of Spring's subclass-based AOP proxies (e.g. via proxy-target-class="true") and @Configuration class support were required to declare an explicit dependency on CGLIB 2.2. As of Spring Framework 3.2, we now repackage and inline the newly-released CGLIB 3.0.

This means greater convenience for users, as well as correct functionality for Java 7 users who are creating subclass proxies of types that contain invokedynamicbytecode instructions. Repackaging CGLIB internally ensures no classpath conflicts with other third party frameworks that may depend on other versions of CGLIB.


Upgrading Project Schemas


This is optional, but another thing you may want to do is to change your Spring XML headers from 3.1 to 3.2 so that the XML schema’s referenced end in -3.2.xsd. For example:

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd

becomes

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

The easiest way of doing this is to use eclipse’s global replace to replace -3.1.xsd with -3.2.xsd, but have a quick check first before you do this…

This change is only really necessary if you want to use any new features that are defined in the 3.2 XML schema files. I made the change just to find out if there were any backward compatibility problems and there weren't, everything seemed fine.


And that's about it. If you need to know about upgrading to Spring 3.1 take a look at this older blog and if you're still using Spring 2.x and want to upgrade to 3 then take a look at this even older blog.

Since this blog was written, the Guys at Spring have released a new version of Spring: 3.2.2-RELEASE

2 comments:

Scott said...

Upgrading Project Schemas -- I find that simply leaving the -x.y off allows the current version to be selected.

Roger Hughes said...

Scott,
Thanks for the comment. Yes, I've noticed that you can miss out the version numbers from end of the schema names, though I'm not sure how long this little change has been there. At one time they were mandatory.