Normally, the cocoon-maven-plugin includes a reloading classloader, so that changes to class files are automatically picked up when do mvn jetty:run
. Just hit refresh and your changes get picked up. It’s just like working in PHP. 🙂
This is OK, but it’s not foolproof. This morning, I saw a few errors of the form “expected class SearchManager, but got class SearchManager”. This is a case of the same class being loaded by a different ClassLoader. Annoyingly, I can no longer reproduce this.
There’s a commercial product, JavaRebel, that aims to do a much better reloading ClassLoader. So, I thought I’d give it a try.
The basic idea to use it is twofold:
- Include the javarebel jar as an agent.
- Stop jetty from auto-reloading.
Of course, this being cocoon, we also have to stop the cocoon-maven-plugin from using its reloading classloader.
The javarebel documentation is quite clear on how to configure maven and jetty. But it makes no mention of cocoon (understandably).
Thankfully, it’s all fairly simple to configure with a maven profile. This makes it easy to call from the command line.
javarebel org.mortbay.jetty maven-jetty-plugin 0 org.apache.cocoon cocoon-maven-plugin false false
With that in place, all that remains is a teeny-tiny shell script to augment the normal call to maven.
#!/bin/sh javarebel_jar="$HOME/javarebel.jar" MAVEN_OPTS="$MAVEN_OPTS -noverify -javaagent:$javarebel_jar" mvn -Pjavarebel "$@"
With this, you can immediately see that javarebel is enabled, as it spits out a big message at startup time. But more importantly, as soon as I change a spring bean (and reload the page that uses it), I get this on the console:
JavaRebel: Reloading class 'com.example.Spigot'. JavaRebel-Spring: Reconfiguring bean 'spigot' [com.example.Spigot]
Hurrah — no errors! It all seems to work rather well. I should probably purchase a licence. 🙂
Update: I’ve seen the error again:
Caused by: org.springframework.beans.PropertyBatchUpdateException; nested PropertyAccessExceptions (1) are:
PropertyAccessException 1: org.springframework.beans.TypeMismatchException: Failed to convert property value of type [com.example.MyService] to required type [com.example.MyService] for property ‘myService’; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [com.example.MyService] to required type [com.example.MyService] for property ‘myService’: no matching editors or conversion strategy found
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:104)
at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:59)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1198)
… 101 more