Matt Matt - 1 month ago 14
Java Question

Missing cxf.xml? Fails in maven, works in Eclipse

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?

Answer

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.