How to package an Apache CXF application into a monolithic JAR with the Maven "shade" plugin

Steve Perkins picture Steve Perkins · Jul 26, 2011 · Viewed 20.1k times · Source

I am writing a console-based Java application, intended to be run by cron in a batch-processing manner. The batch-processing application makes calls to a SOAP web service, using the Apache CXF framework for JAX-WS.

To make deployment easier, and to prevent CLASSPATH issues, I would like to bundle up the application (with all its dependencies) into a single monolithic JAR file... using the "shade" plugin for Maven.

My application works just fine when I run it from my Eclipse workspace. However, when I try executing the shaded JAR file I get a stacktrace such as the following:

org.apache.cxf.service.factory.ServiceConstructionException: Could not resolve a binding for null 
            at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createBindingInfo(AbstractWSDLBasedEndpointFactory.java:404) 
            at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpointInfo(AbstractWSDLBasedEndpointFactory.java:258) 
            at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createEndpoint(AbstractWSDLBasedEndpointFactory.java:146) 
            at org.apache.cxf.frontend.ClientFactoryBean.create(ClientFactoryBean.java:52) 
            at org.apache.cxf.frontend.ClientProxyFactoryBean.create(ClientProxyFactoryBean.java:102) 
            at org.apache.cxf.jaxws.JaxWsProxyFactoryBean.create(JaxWsProxyFactoryBean.java:115) 
            at com.example.gui.domain.Session.getService(Session.java:145) 
            at com.example.gui.domain.service.soap.AbstractServiceImpl.<init>(AbstractServiceImpl.java:23) 
            at com.example.gui.domain.service.soap.GetUserConsoleOrgsImpl.<init>(GetUserConsoleOrgsImpl.java:14) 
            at com.example.gui.domain.service.ServiceFactory.getGetUserConsoleOrgsService(ServiceFactory.java:443) 
            at com.example.gui.domain.AccessManager.getOrgs(AccessManager.java:62) 
            at com.example.gui.windows.ConsoleApplet.login (ConsoleApplet.java:1253) 
            at com.example.gui.windows.ConsoleApplet.init(ConsoleApplet.java:1227) 
            at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source) 
            at java.lang.Thread.run(Unknown Source) 
Caused by: org.apache.cxf.BusException: No binding factory for namespace http://schemas.xmlsoap.org/soap/ registered. 
            at org.apache.cxf.binding.BindingFactoryManagerImpl.getBindingFactory(BindingFactoryManagerImpl.java:91) 
            at org.apache.cxf.frontend.AbstractWSDLBasedEndpointFactory.createBindingInfo(AbstractWSDLBasedEndpointFactory.java:394) 
            ... 14 more 
java.lang.NullPointerException 
            at com.example.gui.domain.service.soap.GetUserConsoleOrgsImpl.getUserConsoleOrgs(GetUserConsoleOrgsImpl.java:29) 
            at com.example.gui.domain.AccessManager.getOrgs(AccessManager.java:64) 
            at com.example.gui.windows.ConsoleApplet.login (ConsoleApplet.java:1253) 
            at com.example.gui.windows.ConsoleApplet.init(ConsoleApplet.java:1227) 
            at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source) 
            at java.lang.Thread.run(Unknown Source) 

In fact, if you check out this discussion board message, I'm having the exact same problem that this guy is having. As another person pointed out in that that thread, my issue is probably with the Maven "shade" plugin.

Apache CXF consists of numerous JAR file dependencies, and apparently more than one of those JAR's rely on contents within their META-INF directories. The Maven "shade" plugin is apparently collapsing all those META-INF directories into one, and overwriting necessary files rather than merging them together.

Someone in that discussion thread provided a link to this Maven POM file, showing that there are config options and transformers for making the "shade" plugin merge these CXF dependencies properly. I plugged these these settings into my own POM, like so:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>1.4</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.example.MainClass</mainClass>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer">
                        <projectName>Apache CXF</projectName>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.handlers</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/com.sun.tools.xjc.Plugin</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.schemas</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/cxf/cxf.extension</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                        <resource>META-INF/extensions.xml</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                        <resource>META-INF/cxf/extensions.xml</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/cxf/bus-extensions.txt</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                        <resource>META-INF/cxf/bus-extensions.xml</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                        <resource>META-INF/wsdl.plugin.xml</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                        <resource>META-INF/tools.service.validator.xml</resource>
                    </transformer>
                    <transformer implementation="org.apache.cxf.maven.PluginTransformer">
                        <resource>META-INF/tools-plugin.xml</resource>
                    </transformer>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                        <resource>META-INF/cxf/java2wsbeans.xml</resource>
                    </transformer>
                    <transformer implementation="org.apache.cxf.maven.CXFAllTransformer" />
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

However, I can't find any real explanation for what these settings are doing... and I get the following error when running Maven with debug output enabled:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1:14.357s
[INFO] Finished at: Tue Jul 26 11:10:43 EDT 2011
[INFO] Final Memory: 18M/59M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:1.4:shade (default) on project salestax-poster: Unable to parse configuration of mojo org.apache.maven.plugins:maven-shade-plugin:1.4:shade: ClassNotFoundException: Class name which was explicitly given in configuration using 'implementation' attribute: 'org.apache.cxf.maven.PluginTransformer' cannot be loaded -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:1.4:shade (default) on project salestax-poster: Unable to parse configuration of mojo org.apache.maven.plugins:maven-shade-plugin:1.4:shade: ClassNotFoundException: Class name which was explicitly given in configuration using 'implementation' attribute: 'org.apache.cxf.maven.PluginTransformer' cannot be loaded
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:221)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
...

It seems to complain that it can't find the org.apache.cxf.maven.PluginTransformer class, which seems to exist in the cxf-buildtools package. However, when I add that package to the POM's dependencies, I get yet another error in the build process:

Jul 26, 2011 10:44:02 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31: display name [org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31]; startup date [Tue Jul 26 10:44:02 EDT 2011]; root of context hierarchy
Jul 26, 2011 10:44:02 AM org.apache.cxf.bus.spring.BusApplicationContext getConfigResources
INFO: No cxf.xml configuration file detected, relying on defaults.
Jul 26, 2011 10:44:02 AM org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory
INFO: Bean factory for application context [org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31]: org.springframework.beans.factory.support.DefaultListableBeanFactory@47fe1e26
Jul 26, 2011 10:44:02 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@47fe1e26: defining beans [cxf,org.apache.cxf.bus.spring.BusApplicationListener,org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor,org.apache.cxf.bus.spring.Jsr250BeanPostProcessor,org.apache.cxf.bus.spring.BusExtensionPostProcessor,org.apache.cxf.resource.ResourceManager,org.apache.cxf.configuration.Configurer,org.apache.cxf.binding.BindingFactoryManager,org.apache.cxf.transport.DestinationFactoryManager,org.apache.cxf.transport.ConduitInitiatorManager,org.apache.cxf.wsdl.WSDLManager,org.apache.cxf.phase.PhaseManager,org.apache.cxf.workqueue.WorkQueueManager,org.apache.cxf.buslifecycle.BusLifeCycleManager,org.apache.cxf.endpoint.ServerRegistry,org.apache.cxf.endpoint.ServerLifeCycleManager,org.apache.cxf.endpoint.ClientLifeCycleManager,org.apache.cxf.transports.http.QueryHandlerRegistry,org.apache.cxf.endpoint.EndpointResolverRegistry,org.apache.cxf.headers.HeaderManager,org.apache.cxf.catalog.OASISCatalogManager,org.apache.cxf.endpoint.ServiceContractResolverRegistry]; root of factory hierarchy
[DEBUG] 
java.lang.AbstractMethodError: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object;
    at org.apache.cxf.tools.validator.internal.Stax2DOM.startElement(Stax2DOM.java:173)
    at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:135)
    at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:95)
    at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:76)
    at org.apache.cxf.tools.validator.internal.WSDL11Validator.getWSDLDoc(WSDL11Validator.java:91)
    at org.apache.cxf.tools.validator.internal.WSDL11Validator.isValid(WSDL11Validator.java:111)
    at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:201)
    at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:61)
    at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:132)
    at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:238)
    at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:83)
    at org.apache.cxf.tools.wsdlto.WSDLToJava.run(WSDLToJava.java:103)
    at org.apache.cxf.maven_plugin.WSDL2JavaMojo.processWsdl(WSDL2JavaMojo.java:360)
    at org.apache.cxf.maven_plugin.WSDL2JavaMojo.execute(WSDL2JavaMojo.java:257)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    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:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Jul 26, 2011 10:44:03 AM org.springframework.context.support.AbstractApplicationContext doClose
INFO: Closing org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31: display name [org.apache.cxf.bus.spring.BusApplicationContext@3aa42c31]; startup date [Tue Jul 26 10:44:02 EDT 2011]; root of context hierarchy
Jul 26, 2011 10:44:03 AM org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons
INFO: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@47fe1e26: defining beans [cxf,org.apache.cxf.bus.spring.BusApplicationListener,org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor,org.apache.cxf.bus.spring.Jsr250BeanPostProcessor,org.apache.cxf.bus.spring.BusExtensionPostProcessor,org.apache.cxf.resource.ResourceManager,org.apache.cxf.configuration.Configurer,org.apache.cxf.binding.BindingFactoryManager,org.apache.cxf.transport.DestinationFactoryManager,org.apache.cxf.transport.ConduitInitiatorManager,org.apache.cxf.wsdl.WSDLManager,org.apache.cxf.phase.PhaseManager,org.apache.cxf.workqueue.WorkQueueManager,org.apache.cxf.buslifecycle.BusLifeCycleManager,org.apache.cxf.endpoint.ServerRegistry,org.apache.cxf.endpoint.ServerLifeCycleManager,org.apache.cxf.endpoint.ClientLifeCycleManager,org.apache.cxf.transports.http.QueryHandlerRegistry,org.apache.cxf.endpoint.EndpointResolverRegistry,org.apache.cxf.headers.HeaderManager,org.apache.cxf.catalog.OASISCatalogManager,org.apache.cxf.endpoint.ServiceContractResolverRegistry]; root of factory hierarchy
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.152s
[INFO] Finished at: Tue Jul 26 10:44:03 EDT 2011
[INFO] Final Memory: 10M/59M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.cxf:cxf-codegen-plugin:2.2:wsdl2java (generate-sources) on project salestax-poster: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object; -> [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.cxf:cxf-codegen-plugin:2.2:wsdl2java (generate-sources) on project salestax-poster: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object;
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:217)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:319)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:156)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:537)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:196)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:141)
    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:290)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Caused by: org.apache.maven.plugin.MojoExecutionException: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object;
    at org.apache.cxf.maven_plugin.WSDL2JavaMojo.processWsdl(WSDL2JavaMojo.java:363)
    at org.apache.cxf.maven_plugin.WSDL2JavaMojo.execute(WSDL2JavaMojo.java:257)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:101)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:209)
    ... 19 more
Caused by: java.lang.AbstractMethodError: org.apache.xerces.dom.ElementNSImpl.setUserData(Ljava/lang/String;Ljava/lang/Object;Lorg/w3c/dom/UserDataHandler;)Ljava/lang/Object;
    at org.apache.cxf.tools.validator.internal.Stax2DOM.startElement(Stax2DOM.java:173)
    at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:135)
    at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:95)
    at org.apache.cxf.tools.validator.internal.Stax2DOM.getDocument(Stax2DOM.java:76)
    at org.apache.cxf.tools.validator.internal.WSDL11Validator.getWSDLDoc(WSDL11Validator.java:91)
    at org.apache.cxf.tools.validator.internal.WSDL11Validator.isValid(WSDL11Validator.java:111)
    at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:201)
    at org.apache.cxf.tools.wsdlto.frontend.jaxws.wsdl11.JAXWSDefinitionBuilder.validate(JAXWSDefinitionBuilder.java:61)
    at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:132)
    at org.apache.cxf.tools.wsdlto.WSDLToJavaContainer.execute(WSDLToJavaContainer.java:238)
    at org.apache.cxf.tools.common.toolspec.ToolRunner.runTool(ToolRunner.java:83)
    at org.apache.cxf.tools.wsdlto.WSDLToJava.run(WSDLToJava.java:103)
    at org.apache.cxf.maven_plugin.WSDL2JavaMojo.processWsdl(WSDL2JavaMojo.java:360)
    ... 22 more

Has anyone ever used Apache CXF in the context of a Maven shaded JAR, and can provide some guidance as to how you make this work properly?

Answer

Eugen picture Eugen · May 3, 2013

In my case I needed to add only:

<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
     <resource>META-INF/cxf/bus-extensions.txt</resource>
</transformer>

If you take a look at this file with and without transformer tag there is a big difference (only one line vs ~50 lines), in particular lines:

org.apache.cxf.binding.soap.SoapBindingFactory::true
org.apache.cxf.binding.soap.SoapTransportFactory::true

are missing which I believe is causing the problem.