I am building a project in Eclipse, using Apache CXF JAX-RS. When I run my main class in Eclipse, it works fine. When I build a jar with dependencies in maven, it doesn't work. This is my pom.xml (I am building by running "mvn clean compile assembly:single"):
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.theopentutorials.jaxrs</groupId>
<artifactId>JsonCxfProvider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-rs-extension-providers</artifactId>
<version>2.7.4</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.3</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.theopentutorials.jaxrs.calc.CalcRESTStartUp</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
This is my main class:
public static void main(String[] args) {
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(ResultsXml.class);
sf.setResourceProvider(ResultsXml.class, new SingletonResourceProvider(new ResultsXml()));
sf.setAddress("http://localhost:9999/open/");
Server server = sf.create();
}
Where ResultsXml is basically an annotated pojo class. When running in Eclipse, I can make requests on localhost:9999/open/ and I get the JSON back that I expect. However, when I build in maven and then run with java -jar myjarfile.jar, I get the following error:
Exception in thread "main" org.apache.cxf.service.factory.ServiceConstructionException at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:197) at com.theopentutorials.jaxrs.calc.CalcRESTStartUp.main(CalcRESTStartUp.java:15) Caused by: org.apache.cxf.BusException: No DestinationFactory was found for the namespace http://cxf.apache.org/transports/http. at org.apache.cxf.bus.managers.DestinationFactoryManagerImpl.getDestinationFactory(DestinationFactoryManagerImpl.java:130) at org.apache.cxf.endpoint.ServerImpl.initDestination(ServerImpl.java:88) at org.apache.cxf.endpoint.ServerImpl.(ServerImpl.java:72) at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:155) ... 1 more
Everything I have been able to find on Google / StackOverflow so far suggests that this error comes from a missing META-INF/cxf/cxf.xml file - which makes sense, as I don't have one of those. But how then does it work in Eclipse?
Could it be that Eclipse is picking up a cxf.xml file from one of the dependency jars that happens to have the config I need, but when packaging with maven it picks them up in a different order and so doesn't work? I have tried to create my own cxf.xml file, but I'm not sure which one (the maven build logs suggest that between all my dependencies, there are about 12 copies of the file) to use - is there a way to find out which one Eclipse is picking up?
EDIT1
I tried using eclipse to export a runnable jar file with unpacked dependencies, when the eclipse-exported jar I get a similar but subtly different message:
Cannot find any registered HttpDestinationFactory from the Bus. org.apache.cxf.transport.http.HTTPTransportFactory
Exception in thread "main" org.apache.cxf.service.factory.ServiceConstructionException at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:199) at com.theopentutorials.jaxrs.calc.CalcRESTStartUp.main(CalcRESTStartUp.java:15) Caused by: java.io.IOException: Cannot find any registered HttpDestinationFactory from the Bus. at org.apache.cxf.transport.http.HTTPTransportFactory.getDestination(HTTPTransportFactory.java:295) at org.apache.cxf.endpoint.ServerImpl.initDestination(ServerImpl.java:93) at org.apache.cxf.endpoint.ServerImpl.(ServerImpl.java:72) at org.apache.cxf.jaxrs.JAXRSServerFactoryBean.create(JAXRSServerFactoryBean.java:155)
EDIT2
I tried using eclipse to export a runnable jar file with 'package required libraries into jar' - so far this seems to be working. Is it possible to replicate this in maven?
You can find this in Window > Preferences > Maven > User Settings , and then point Global Settings to your external maven settings. xml . Then i removed the broken projects and re-added them, and the Maven Dependencies library appeared again. Save this answer.
For both web service clients and servers, the default location that CXF will look for a configuration for is "/cxf. xml" on the class path. For example, when running your application in a servlet container, this file is expected to be located in a /WEB-INF/classes folder of your web application.
Running the HelloWorld Service This will generate the appropriate Apache CXF classes from your wsdl, compile your Apache CXF classes, deploy the server on the embedded jetty server and run your application. INFO: Setting the server's publish address to be http://localhost:9090/HelloServerPort Server ready...
Via the Maven index, you can search for dependencies, select them and add them to your pom file. To download the index, select Windows > Preferences > Maven and enable the Download repository index updates on startup option. After changing this setting, restart Eclipse. This triggers the download of the Maven index.
It seems the correct fix for this, which I discovered when I had the exact same problem with some Spring libraries, is to use the Maven Shade plugin:
http://maven.apache.org/plugins/maven-shade-plugin/
Because several cxf-* jars have files in them with the same names (eg META-INF/cxf/cxf.xml) a normal jar-with-dependencies build will include the first one, and then ignore all subsequent ones it finds as 'duplicate'. The shade plugin will concatenate these files together, so you end up with one large file at the end that contains all of the entries that you needed.
This maven-shade-plugin configuration worked for me:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!-- Optional Start -->
<finalName>${artifactId}-${version}</finalName>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jar-with-dependencies</shadedClassifierName>
<!-- Optional End -->
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.logslie.main</mainClass>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/cxf-extension-xml.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/cxf-extension-http-jetty.xml</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/cxf-extension-http.xml</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/cxf-servlet.xml</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/cxf.xml</resource>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
I suppose you use the zip created by the maven assembly plugin. When using jar-with-dependencies, this plugin merges all the files from the dependency jars in one single jar file. If there is some file that have the same name and path in the various jars, only one of those duplicated files will be kept. In your case, I think it is the /META-INF/cxf/bus-extensions.txt from cxf-rt-transports-http-jetty jar file which doesn't appear in the resulting assembly zip file. In Eclipse, the merge of the jar files is not done so each bus-extensions.txt is loaded.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With