Atomikos + Jetty in a Maven build environment - Classloader issue?

atomikos, java, jetty, jta, maven-2

Solution

You may have multiple copies of the `UserTransaction` class kicking around in your deployment. If these are loaded from different classloaders, then you can end up with this sort of error.

Check Jetty's libraries for `UserTransaction`, and then check your application's libraries. You should only have one copy.

Problem

I am working on a project with multiple JDBC data sources and JTA. I use Maven as a build tool, and I'd like to use the Jetty plugin (6.1.20) to run the application during development. I am trying to configure Jetty to use Atomikos as the transaction manager. I'm following the Atomikos documentation from Jetty, but the Jetty startup fails with what looks like a class loader issue. Here are the relevant bits of my configuration. `runtime` scope dependencies in my `pom.xml`: ``` <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jta</artifactId> <version>3.5.7</version> <scope>runtime</scope> </dependency> <dependency> <groupId>com.atomikos</groupId> <artifactId>transactions-jdbc</artifactId> <version>3.5.7</version> <scope>runtime</scope> </dependency> <dependency> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> <version>1.1</version> <scope>runtime</scope> </dependency> ``` My `jetty-env.xml` located in `/WEB-INF` (autodiscovered by Jetty): ``` <New id="userTxImpl" class="com.atomikos.icatch.jta.UserTransactionImp" /> <New id="tx" class="org.mortbay.jetty.plus.naming.Transaction"> <Arg> <Ref id="userTxImpl" /> </Arg> </New> ``` The instantiation of `tx` at the end is the bit that fails, if I leave it out, Jetty starts up fine (but does not expose `UserTransaction` via JNDI, of course). The Stacktrace: ``` 2009-09-02 18:42:18.910::WARN: Config error at <New id="tx" class="org.mortbay.jetty.plus.naming.Transaction"><Arg> <Ref id="userTxImpl"/> </Arg></New> 2009-09-02 18:42:18.910::WARN: Failed startup of context org.mortbay.jetty.plugin.Jetty6PluginWebAppContext@12515db{/administrator,C:\workspace\administrator\src\main\webapp} java.lang.IllegalStateException: No Constructor: <New id="tx" class="org.mortbay.jetty.plus.naming.Transaction"><Arg> <Ref id="userTxImpl"/> </Arg></New> on org.mortbay.jetty.plugin.Jetty6PluginWebAppContext@12515db{/administrator,C:\workspace\administrator\src\main\webapp} at org.mortbay.xml.XmlConfiguration.newObj(XmlConfiguration.java:631) at org.mortbay.xml.XmlConfiguration.configure(XmlConfiguration.java:256) at org.mortbay.xml.XmlConfiguration.configure(XmlConfiguration.java:190) at org.mortbay.jetty.plus.webapp.EnvConfiguration.configureWebApp(EnvConfiguration.java:130) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1247) at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517) at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467) at org.mortbay.jetty.plugin.Jetty6PluginWebAppContext.doStart(Jetty6PluginWebAppContext.java:124) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152) at org.mortbay.jetty.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:156) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.jetty.Server.doStart(Server.java:224) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.plugin.Jetty6PluginServer.start(Jetty6PluginServer.java:132) at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:441) at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:383) at org.mortbay.jetty.plugin.AbstractJettyRunMojo.execute(AbstractJettyRunMojo.java:210) at org.mortbay.jetty.plugin.Jetty6RunMojo.execute(Jetty6RunMojo.java:184) at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPluginManager.java:579) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHandleFailures(DefaultLifecycleExecutor.java:498) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegmentForProject(DefaultLifecycleExecutor.java:265) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegments(DefaultLifecycleExecutor.java:191) at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLifecycleExecutor.java:149) at org.apache.maven.DefaultMaven.execute_aroundBody0(DefaultMaven.java:223) at org.apache.maven.DefaultMaven.execute_aroundBody1$advice(DefaultMaven.java:304) at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:1) at org.apache.maven.embedder.MavenEmbedder.execute_aroundBody2(MavenEmbedder.java:904) at org.apache.maven.embedder.MavenEmbedder.execute_aroundBody3$advice(MavenEmbedder.java:304) at org.apache.maven.embedder.MavenEmbedder.execute(MavenEmbedder.java:1) at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:176) at org.apache.maven.cli.MavenCli.main(MavenCli.java:63) 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.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289) at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229) at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:408) at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:351) at org.codehaus.classworlds.Launcher.main(Launcher.java:31) ``` This looks like a classloader issue, as `org.mortbay.jetty.plus.naming.Transaction` has got a Constructor taking a `javax.transaction.UserTransaction`, and `com.atomikos.icatch.jta.UserTransactionImp` implements `javax.transaction.UserTransaction`, yet Jetty complains it does not have a proper constructor to use. I'm obviously missing something here, but what is it? Thanks!

Original source