spring-cloud-netflix icon indicating copy to clipboard operation
spring-cloud-netflix copied to clipboard

Support jersey 2 for eureka

Open nodje opened this issue 8 years ago • 17 comments

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 ??

nodje avatar Feb 23 '16 05:02 nodje

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.

dsyer avatar Feb 23 '16 11:02 dsyer

Do we document that ribbon and eureka use jersey and therefor could conflict?

spencergibb avatar Mar 03 '16 01:03 spencergibb

I guess so. Note that it's only a problem with eureka server as far as I know (which has never been very embeddable).

dsyer avatar Mar 03 '16 07:03 dsyer

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.

maihacke avatar May 01 '16 07:05 maihacke

Yeah, that's right, sorry. You can't use ribbon with JAX-RS 2.0.

dsyer avatar May 01 '16 08:05 dsyer

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 avatar May 24 '16 05:05 nodje

@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.

spencergibb avatar May 24 '16 14:05 spencergibb

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.

spencergibb avatar Jun 24 '16 02:06 spencergibb

Update in this thread, looks like Eureka Client 1.6 will be compatible: https://github.com/Netflix/eureka/pull/821

voor avatar Oct 26 '16 14:10 voor

@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 avatar Dec 19 '16 05:12 aksain

@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 avatar Dec 20 '16 18:12 spencergibb

@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 -

  1. In CloudEurekaClient.java - Replaced DiscoveryClientOptionalArgs with AbstractDiscoveryClientOptionalArgs
  2. 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
  3. In EurekaClientAutoConfiguration - Replaced DiscoveryClientOptionalArgs with AbstractDiscoveryClientOptionalArgs

aksain avatar Dec 25 '16 03:12 aksain

@aksain Pull Requests are welcome.

spencergibb avatar Jan 09 '17 16:01 spencergibb

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.

michael-simons avatar May 29 '18 12:05 michael-simons

Same problem from me. Is there any roadmap, news about a migration path ?

jlelong-onepoint avatar Nov 19 '20 11:11 jlelong-onepoint

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.

dsyer avatar Nov 19 '20 11:11 dsyer

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

jlelong-onepoint avatar Nov 19 '20 13:11 jlelong-onepoint