Spring @PathVariable Head-slapper

A simple oversight in the documentation and potentially unnecessary default in the Spring @PathVariable annotation can cause runtime trouble..

Object Partners

Recently some peers and I spent a little time spinning around a goofy little annotation trick that Spring uses, that bit us because of the way p-code is generated. It all makes sense afterwards, but at the time it was a little frustrating and puzzling.

Taken straight from the Spring documentation, the following example shows a similar use to what we’d done.

`@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {`
  Owner owner = ownerService.findOwner(ownerId);
  model.addAttribute("owner", owner);
  return "displayOwner";
}

Our code looked pretty much the same, with our names and useful bits, of course. Quickly scanning that documentation shows that our syntax was accurate. The compiler didn’t complain, and sometimes it worked. Where it got confusing is that the code would work just fine when run in an integration test using HTTPUnit (in the IDE and run by Ant) and in a Servlet engine (Tomcat, specifically) when launched from Eclipse. Some people had success when deploying to Tomcat using an Eclipse-created WAR file, but some people experienced failure. Everyone failed when using the Ant-built WAR file.

When the error occurred, the root cause of the Exception caught ultimately was the following:

java.lang.IllegalStateException: No parameter name specified for argument of type [java.lang.String], and no parameter name information found in class file either.

When you look at the code, you can see the @RequestMapping has the appropriate {variable} notation, and that the parameter list has a variable of the same name, of type String, as expected (other types can be used, but ours was a String also).

A peek at the Ant script gave a clue to the solution. Changing the javac target’s debug attribute to “on” allowed the Ant-built WAR file to also deploy and run with success. That’s when the head-slapping began.

When the code is compiled with debug, as it is when working in the IDE, and apparently is sometimes when exporting from the IDE (probably some of us have a workspace setting different than the others), the name of the parmeter is available to the JVM at runtime. When the code is compiled without debugging, as the Ant script was doing, then the parameter name is lost, truncated by the p-code generator based on its type and order and other factors.

Adding the name to the @PathVariable annotation allows the runtime to find the correct parameter even without debug information in the class file. Again, straight from the same documentation, just a couple paragraphs down from the other example shows the more correct way to declare the @PathVariable. Right above the example on their page is a discrete mention of this fact, and a recommendation that you specify the name. Below is the subtle difference in the declaration, one that makes all the difference.

@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable("ownerId") String ownerId, Model model) {
  // implementation omitted
}

While it’s convenient to have Spring work this out for you during the development cycle, it seems more appropriate that the value be required which can be achieved simply by removing the default from the annotation. Since it isn’t that way, it’s certainly a good practice to get into to always provide the name (or names) of your path variable when annotating your controllers in Spring.

Share this Post

Related Blog Posts

JVM

How Do Annotations Work?

August 6th, 2010

A quick trip through some examples of how to define, find, and ultimately use annotations to get work done on diverse classes.

Object Partners
JVM

Packaging your Java application for the Mac

August 3rd, 2010

The Mac has some nice tools to turn your jar file into a first class Mac application. This is most useful if the application has a GUI interface; Swing, SWT, etc. There are three parts to this process: Package your application as a jar file Create an…

Object Partners
JVM

Sun Java 1.6.0_21 Not Detected By Eclipse

July 30th, 2010

A quick-fix to get Eclipse running again after an automatic update makes the Sun JVM again undetectable.

Object Partners

About the author