spring-cloud-netflix
spring-cloud-netflix copied to clipboard
Support jersey 2 for eureka
Using Jersey for the REST layer in a project, I've got a dependency conflict when using Spring Cloud as follow:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
<scope>runtime</scope>
</dependency>
The Spring Boot Jersey dependency org.springframework.boot:spring-boot-starter-jersey:jar:1.3.2.RELEASE
is used.
The error is
java.lang.NoSuchMethodError: javax.ws.rs.core.Application.getProperties()Ljava/util/Map;
at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:331) ~[jersey-server-2.22.1.jar:na]
at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:390) ~[jersey-container-servlet-core-2.22.1.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:172) ~[jersey-container-servlet-core-2.22.1.jar:na]
at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:364) ~[jersey-container-servlet-core-2.22.1.jar:na]
at javax.servlet.GenericServlet.init(GenericServlet.java:158) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
and it comes from the fact that both
-
javax.ws.rs:javax.ws.rs-api:jar:2.0.1:compile
-
javax.ws.rs:jsr311-api:jar:1.1.1:runtime
are present in the classpath.
spring-cloud-starter-zuul
includes jsr311-api.jar
from its ribbon-httpclient
dependency
+- com.netflix.ribbon:ribbon-httpclient:jar:2.1.0:compile
[INFO] | | | +- com.sun.jersey:jersey-client:jar:1.19:runtime
[INFO] | | | | \- com.sun.jersey:jersey-core:jar:1.19:runtime
[INFO] | | | | \- javax.ws.rs:jsr311-api:jar:1.1.1:runtime
[INFO] | | | \- com.sun.jersey.contribs:jersey-apache-client4:jar:1.19:runtime
I solved it by excluding jersey-client
like this
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-apache-client4</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
<scope>runtime</scope>
</dependency>
It works when testing Zuul manually but I'm not sure it would under all conditions.
It's heavy handed but I figure I already have a much newer jersey client org.glassfish.jersey.core:jersey-client:jar:2.22.1:compile
included with Spring Boot Jersey.
Why would ribbon use older Jersey client dependency? Is there any reason it wouldn't work with the newest org.glassfish.jersey.core:jersey-client:jar:2.22.1
??
Why would ribbon use older Jersey client dependency?
You'd have to take that up with the Ribbon devs. Ribbon is a Netflix project.
Is there any reason it wouldn't work with the newest org.glassfish.jersey.core:jersey-client:jar:2.22.1 ?
I'd be very surprised if it worked (it's a major upgrade of a core component), but if you have something that works, that's awesome.
Do we document that ribbon and eureka use jersey and therefor could conflict?
I guess so. Note that it's only a problem with eureka server as far as I know (which has never been very embeddable).
There are additional problems when using ribbon clients.
The exception is
org.springframework.beans.factory.BeanInitializationException: Failed to process @EventListener annotation on bean with name 'ribbonRestClient'; nested exception is java.lang.NoClassDefFoundError: com/sun/jersey/api/client/config/ClientConfig
The cause is that org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration
imports
import com.sun.jersey.api.client.Client; import com.sun.jersey.client.apache4.ApacheHttpClient4;
which belongs to JAX-RS 1.x and is not available in JAX-RS 2.
Yeah, that's right, sorry. You can't use ribbon with JAX-RS 2.0.
I'm stuck with this problem agan. I have to migrate a monolithic app using Jersey 2.0 to a microservice. Has anyone been touch with Netflix about it?
I guess having them migrate their code to use a Jersey 2.0 client is the the best bet to solve this problem.
@nodje see https://github.com/Netflix/eureka/issues/600
Short answer: the code allows an implementation now as there is an abstraction. Netflix isn't keen on building it themselves, but would be open to PR's. We may do some work on this, but it would likely be based on RestTemplate
, not jersey.
For those watching, Netflix has started a jersey 2 client. https://github.com/Netflix/eureka/tree/master/eureka-client-jersey2
Not sure how much more work they are going to do.
Update in this thread, looks like Eureka Client 1.6 will be compatible: https://github.com/Netflix/eureka/pull/821
@spencergibb Can this be included in 1.3.0.M1 milestone as this issue resolution is quite crucial to use Jersey 2 with Spring cloud?
@aksain, probably not. I don't know what is involved to get this to work and haven't had time to look at it.
@spencergibb Alright. For now, I have created one more starter on top of Spring cloud netflix one. Sharing the changes that i had to do, as this could be handy -
- In CloudEurekaClient.java - Replaced DiscoveryClientOptionalArgs with AbstractDiscoveryClientOptionalArgs
- In MutableDiscoveryClientOptionalArgs.java - Made it extend from Jersey2DiscoveryClientOptionalArgs, Replaced ClientFilter with ClientRequestFilter and added a constructor to set TransportClientFactories in super class to Jersey2TransportClientFactories.getInstance() using setTransportClientFactories method
- In EurekaClientAutoConfiguration - Replaced DiscoveryClientOptionalArgs with AbstractDiscoveryClientOptionalArgs
@aksain Pull Requests are welcome.
Having Jersey 1.x on the classpath of a Spring Boot app running JAX-RS on Jetty prevents the application from starting with the Spring Boot Maven plugin. See ticket over here https://github.com/spring-projects/spring-boot/issues/13290. We use Ribbon and not Eureka and at the moment, we're just excluding Jersey-Client 1.x.
Same problem from me. Is there any roadmap, news about a migration path ?
The migration path is to not use Jersey 1.x, I guess (https://cloud.spring.io/spring-cloud-netflix/multi/multi__service_discovery_eureka_clients.html#_eurekaclient_without_jersey). And I guess to not use Ribbon.
The migration path is to not use Jersey 1.x, I guess (https://cloud.spring.io/spring-cloud-netflix/multi/multi__service_discovery_eureka_clients.html#_eurekaclient_without_jersey). And I guess to not use Ribbon.
I had wrongly guess that was not supported as this ticket is open. On my side i have also exclude the jsr311 (jax-rs 1) dependency as my point was to avoid conflict with jax-rs 2. Eureka client and core explicitly depend on it in addition to jersey.
For reference my final gradle configuration is :
implementation('org.springframework.cloud:spring-cloud-starter-netflix-eureka-client') {
exclude group: 'com.sun.jersey'
exclude module: 'jsr311-api'
}
We have now to test in order to assure compatibility between Eureka and jaxrs 2.
Thanks a lots for your help