Friday 23 July 2010

Spring MVC ExceptionHandler needs to be in same class

Had a frustrating evening (pet project) trying to get Spring 3.0 MVC's annotation based exception handler to work.

All the examples seemed straight forwards:

Just annotate a method in a controller:
import org.springframe...ExceptionHandler;
import org.springframe...ModelAndView;
import org.springframe...Controller;
....
@Controller
public class MyController {
....
@ExceptionHandler(SomeException.class)
public ModelAndView myExceptionHandler(
    SomeException exception){
  blah
}
...
}


But it just would never catch my exceptions. Very frustrating.

But in the end a google search to the end of the world where someone mentioned in the comments that the exceptionhandler method have to be be in the same class as the method throwing the exception.

Very odd restriction compared to Spring's usual very agile and generic annotation.

So I added my handlers to my abstract controller class that all my controllers extend and problem solved, with some hair still intact.

Tuesday 20 July 2010

org.hibernate.MappingException: Could not determine type for Set / List

I was simplifying the domain model of a pet project by removing an unneccesarry entity by using JPA 2.0's ElementCollection annotation:

public class SecurityDetail {

public enum AuthorityRole{
  ROLE_ADMIN,
  ROLE_SUPER,
  ROLE_USER
}
....
@ElementCollection
@CollectionTable(
  name="Authority",
  joinColumns=@JoinColumn(name="username")
)
private Set authorities;
....


However I was getting this error message:
org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: SecurityDetail, for columns: [org.hibernate.mapping.Column(authorities)]


Digging around (googling) I ended up on this blog entry: blog.m1key.me/2010/06/orghibernatemappingexception-could-not.html, which main solution is to make sure you have a newer hibernate, version 3.5.3 or later.


I use maven, with the hibernate3-maven-plugin, sql-maven-plugin and dbunit-maven-plugin to create the schema, database and to populate data. So I bumped the org.hibernate:hibernate-entitymanager dependency from 3.5.0 to 3.5.3-Final. (and fixed my own nexus repository to pull JBoss's latest jars.)

However it did not fix the problem. But by reading the comments of the blog entry above I also realised that my hibernate3-maven-plugin may be using older dependencies. So I explicitly added the recent verions of org.hibernate:hibernate-core dependency to both the plugin and the app, as well as org.hibernate:hibernate-entitymanager to the plugin as well:

<properties>
  <hibernate.version>3.5.3-Final</hibernate.version>
</properties>
....
<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-entitymanager</artifactId>
    <version>${hibernate.version}</version>
    <exclusions>
      <exclusion>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
      </exclusion>
      <exclusion>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>${hibernate.version}</version>
    <exclusions>
      <exclusion>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
      </exclusion>
      <exclusion>
        <groupId>commons-logging</groupId>
        <artifactId>commons-logging</artifactId>
      </exclusion>
    </exclusions>
  </dependency>
</dependencies>
....
<plugins>
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>hibernate3-maven-plugin</artifactId>
    <version>2.2</version>
    <executions>
      <execution>
        <phase>process-classes</phase>
        <goals>
          <goal>hbm2ddl</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <components>
        <component>
          <name>hbm2ddl</name>
          <implementation>jpaconfiguration</implementation>
        </component>
      </components>
      <componentProperties>
        <persistenceunit>${project.artifactId}</persistenceunit>
        <outputfilename>schema.ddl</outputfilename>
        <drop>false</drop>
        <create>true</create>
        <export>false</export>
        <format>true</format>
      </componentProperties>
    </configuration>
    <dependencies>
      <dependency>
        <groupId>hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <version>${hsqldb.version}</version>
      </dependency>
      <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
        <exclusions>
          <exclusion>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
          </exclusion>
          <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
      <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
        <exclusions>
          <exclusion>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
          </exclusion>
          <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
    </dependencies>
  </plugin>
</plugins>

Friday 16 July 2010

Groovy for DSL

Started reading through Groovy for Domain Specific Languages, a new book by Fergal Dearle. As I interested in how to apply Groovy in more enterprise applications I would have normally liked to read this book, however I was also asked to write a review of the book, so Id better read it! How to keep DSLs easy to read while easy to create and maintain with Groovy will be something I hope this book covers.

The book was also reviewed on slashdot recently.

You can read the free chapter or buy the book yourself at e.g. amazon.co.uk, amazon.com or Packt.

Any comments of others interested in Groovy, especially in the DSL area are very welcome?

Friday 2 July 2010

Skinny WAR Assembly in maven

If you want to create a "Skinny WAR" so that you can package it as part of an EAR or as in my case as part of an assembly later, then you can do this:


<plugin>
   <artifactId>maven-war-plugin</artifactId>
   <version>2.1-beta-1</version>
   <configuration>
     <packagingExcludes>WEB-INF/lib/*.jar</packagingExcludes>
     <archive>
       <manifest>
         <addClasspath>true</addClasspath>
         <classpathPrefix>lib/</classpathPrefix>
       </manifest>
     </archive>
   </configuration>
</plugin>


If you then later in another pom.xml want to include this war and the excluded libraries:


<dependency>
   <groupId>${project.groupId}</groupId>
   <artifactId>you war module name</artifactId>
   <version>${project.version}</version>
   <type>war</type>
</dependency>
<dependency>
   <groupId>${project.groupId}</groupId>
   <artifactId>you war module name</artifactId>
   <version>${project.version}</version>
   <type>pom</type>
</dependency>

Maven Jetty and Tomcat dependencies with JSP / JSTL errors

I use Jetty as a Maven plugin during development, but tend to run Tomcat as my deployment server. (Not sure "production" is appropiate as it's my personal server). My applications are often java MVC based utilising some form of JSP.

This combination creates a slight issue with dependencies for JSP and JSTL. If you have ever seen this error when running mvn jetty:run:

java.lang.ClassNotFoundException: org.apache.el.ExpressionFactoryImpl

Or these errors when running in tomcat when it was okay in jetty:

javax.servlet.jsp.JspApplicationContext
.getExpressionFactory()Ljavax/el/ExpressionFactory


or

org.apache.jasper.JasperException: Unable to read TLD "META-INF/c.tld" from JAR file

or

java.lang.LinkageError: loader constraint violation: loader (instance of org/apache/catalina/loader/WebappClassLoader) previously initiated loading for a different type with name "javax/el/ExpressionFactory"

Over the last few years I have perservered and solved this flat wheel in different ways. However in my recent deja-vue I now have a tidy solution. (the project where this is visable is my up4 project. github source, demo)

I am utilising the jetty maven plugin, and the tomcat maven plugin to show how this works.


<plugin>
<groupId>org.mortbay.jetty</groupId>
   <artifactId>jetty-maven-plugin</artifactId>
   <version>7.0.2.v20100331</version>
</plugin>
<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>tomcat-maven-plugin</artifactId>
</plugin>


To utilise JSP pages and JSTL EL with e.g. Spring MVC / Struts Tiles you perhaps expect these types of maven dependencies, remembering that most containers include support for Servelet API and JSPs:


<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>compile</scope>
</dependency>
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
</dependency>


If you then try mvn clean jetty:run you may end up with a:

java.lang.ClassNotFoundException: org.apache.el.ExpressionFactoryImpl

A response which will solve the jetty problem is to include some jstl EL dependencies:


<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>compile</scope>
</dependency>
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
</dependency>
<dependency>
   <groupId>org.apache.tomcat</groupId>
   <artifactId>jasper-el</artifactId>
   <version>6.0.26</version>
</dependency>


mvn jetty:run

This should now work fine in Jetty (test in browser as well).

Now try the application in tomcat: mvn clean tomcat:run . It will moan about unable to read some the JSTL taglibs:

org.apache.jasper.JasperException: Unable to read TLD "META-INF/c.tld" from JAR file

This due to the compile scope of the jsp-api dependency, changing this to provided:


<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
</dependency>
<dependency>
   <groupId>org.apache.tomcat</groupId>
   <artifactId>jasper-el</artifactId>
   <version>6.0.26</version>
</dependency>


Test first in mvn jetty:run , which should be okay.

Then in mvn clean tomcat:run . It starts ok, but on the first browser test this error appears:

javax.servlet.jsp.JspApplicationContext
.getExpressionFactory()Ljavax/el/ExpressionFactory


Okay, so Tomcat does not like JSTL EL dependencies as it provides them itself, so my initial respone was to have a separate profile which changed the scope of the dependency to provided for tomcat builds only. However on further reflection it turns out the spec says JSP & EL should be provided by the container. So in fact the problem lays with Jetty, and it turns out the move to eclipse.org created a licensing issue with JSP, so jetty does not include the appropiate libs. So to fix this the correct dependencies will have to be:

In your plugins section:


<plugin>
   <groupId>org.mortbay.jetty</groupId>
   <artifactId>jetty-maven-plugin</artifactId>
   <version>7.0.2.v20100331</version>
   <dependencies>
     <dependency>
       <groupId>org.mortbay.jetty</groupId>
       <artifactId>jsp-2.1-glassfish</artifactId>
       <version>9.1.1.B60.25.p2</version>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
       <artifactId>el-api</artifactId>
       <version>6.0.26</version>
     </dependency>
     <dependency>
       <groupId>org.apache.tomcat</groupId>
       <artifactId>jasper-el</artifactId>
       <version>6.0.26</version>
     </dependency>
   </dependencies>
</plugin>


And in your normal dependencies section:


<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>2.5</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>javax.servlet.jsp</groupId>
   <artifactId>jsp-api</artifactId>
   <version>2.1</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
</dependency>
<dependency>
   <groupId>org.apache.tomcat</groupId>
   <artifactId>el-api</artifactId>
   <version>6.0.26</version>
   <scope>provided</scope>
</dependency>
<dependency>
   <groupId>org.apache.tomcat</groupId>
   <artifactId>jasper-el</artifactId>
   <version>6.0.26</version>
   <scope>provided</scope>
</dependency>


mvn jetty:run & mvn tomcat:run

Voila.


Ps. If you are providing a WAR for another jetty container, you may want to create a profile section which include the provided dependencies.

Ps2. If you prefer Sun's EL libs then replace the org.apache.tomcat dependencies with:

<dependency>
   <groupId>javax.el</groupId>
   <artifactId>el-api</artifactId>
   <version>2.2</version>
   <scope>compile</scope>
</dependency>
<dependency>
   <groupId>org.glassfish.web</groupId>
   <artifactId>el-impl</artifactId>
   <scope>runtime</scope>
   <version>2.2</version>
</dependency>