jersey
  1. jersey
  2. JERSEY-1377

Interaction of jersey server with multipart with cxf client fails

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.12
    • Fix Version/s: 1.19
    • Component/s: None
    • Labels:
      None
    • Environment:

      Windows 7 and tomcat 7

      Description

      When using a jersey client to retrieve multipart from a jersey server in a jersey-client/cxf mixed app reports that there is a missing start boundary.

      After debugging I found that MediaType in jsr311-api-1.0.jar (used by cxf 2.2.2) is converting headers to lowercase. Since com.sun.jersey.multipart.Boundary.java is generating boundaries as
      return new StringBuilder("Boundary_").
      append(boundaryCounter.incrementAndGet()).
      append('_').
      append(new Object().hashCode()).
      append('_').
      append(System.currentTimeMillis()).
      toString();
      }

      with an Upper case "Boundary", cxf would fail to find it in the body after the boundary case in the Content-Type is lowercased.

      I am using jersey-client, yet javax.ws.rs is loaded from cxf given that the META-INF/services/javax.ws.rs.ext.RuntimeDelegate is found first in cxf and not in jersey-core.(I suspect that the web loader in tomcat finds "c" before "j")

      Jersey's header and body are practically OK. It would be a cxf bug, except that it has to do with classpath conflicts between cxf and jersey-client. This could be easily fixed in Jersey by producing an all lowercase boundary.

      The actual issue is that I have a legacy app that mixes both cfx and jersey-client. IMPORTANT: I am using the jersey client but cxf takes over. It would be OK for cfx to take over and it would do the right thing had it been lowercase.

      The current workaround is to:
      extract jersey's javax.ws.rs.ext.RuntimeDelegate
      build the client WAR with the structure WEB-INF/classes/META-INF/services/javax.ws.rs.ext.RuntimeDelegate
      start the app.

      This is not entirely proper since the portions of the legacy application that use cxf would load jersey javax.ws.rs now.

      The real fix is to force jersey-client to load its own classes, not going to the RuntimeDelegate et al to get the class names it requires. Going to get class names for RuntimeDelegate breaks jersey's encapsulation. It is an invitation for bugs.

        Activity

        Hide
        Martin Matula added a comment -

        OK, so the issue is that the Jersey uses RuntimeDelegate to get internal classes instead of just using them directly. And you are saying if we fix this, it will fix the issue, right?
        Note that JAX-RS API itself uses RuntimeDelegate, so if it is in fact not the jersey client, but the jax-rs api that calls RuntimeDelegate, we can't fix it. Do you have any particular calls to RuntimeDelegate in mind?

        Show
        Martin Matula added a comment - OK, so the issue is that the Jersey uses RuntimeDelegate to get internal classes instead of just using them directly. And you are saying if we fix this, it will fix the issue, right? Note that JAX-RS API itself uses RuntimeDelegate, so if it is in fact not the jersey client, but the jax-rs api that calls RuntimeDelegate, we can't fix it. Do you have any particular calls to RuntimeDelegate in mind?
        Hide
        Michal Gajdos added a comment -

        Actually converting headers to lowercase is not done by javax.ws.rs.core.MediaType but the problem is in CXF (and because of the fact that RuntimeDelegate service class is picked up from CXF instead of Jersey).

        org.apache.cxf.jaxrs.impl.MediaTypeHeaderProvider from CXF is responsible for parsing header lines and creating MediaType instance using the MediaType(String type, String subtype, Map<String, String> parameters) constructor. At this point the parameter names and values are already in lowercase (see [1] line 67-68).

        Before touching anything in the Jersey code, can you change the version of CXF you're using? It seems that this problem has been fixed in CXF 2.2.5 (see [2], lines 67-68).

        [1] http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-rt-frontend-jaxrs/2.2.2/org/apache/cxf/jaxrs/impl/MediaTypeHeaderProvider.java#67
        [2] http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-rt-frontend-jaxrs/2.2.5/org/apache/cxf/jaxrs/impl/MediaTypeHeaderProvider.java#67

        Show
        Michal Gajdos added a comment - Actually converting headers to lowercase is not done by javax.ws.rs.core.MediaType but the problem is in CXF (and because of the fact that RuntimeDelegate service class is picked up from CXF instead of Jersey). org.apache.cxf.jaxrs.impl.MediaTypeHeaderProvider from CXF is responsible for parsing header lines and creating MediaType instance using the MediaType(String type, String subtype, Map<String, String> parameters) constructor. At this point the parameter names and values are already in lowercase (see [1] line 67-68). Before touching anything in the Jersey code, can you change the version of CXF you're using? It seems that this problem has been fixed in CXF 2.2.5 (see [2] , lines 67-68). [1] http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-rt-frontend-jaxrs/2.2.2/org/apache/cxf/jaxrs/impl/MediaTypeHeaderProvider.java#67 [2] http://grepcode.com/file/repo1.maven.org/maven2/org.apache.cxf/cxf-rt-frontend-jaxrs/2.2.5/org/apache/cxf/jaxrs/impl/MediaTypeHeaderProvider.java#67
        Hide
        Michal Gajdos added a comment -

        The issue with wrong RuntimeDelegate instance cannot be fixed in Jersey code in this case. As I mentioned the problem is in HeaderDelegate<MediaType> implementation present in CXF and an instance of this class is obtained and held in MediaType class itself (see [1], lines 44-45) which is in JAX-RS API.

        One thing you can do is to set the RuntimeDelegate instance yourself (before any other Jersey code is invoked):

        RuntimeDelegate.setInstance(new com.sun.ws.rs.ext.RuntimeDelegateImpl());
        

        [1] http://grepcode.com/file/repo1.maven.org/maven2/javax.ws.rs/jsr311-api/1.1.1/javax/ws/rs/core/MediaType.java#44

        Show
        Michal Gajdos added a comment - The issue with wrong RuntimeDelegate instance cannot be fixed in Jersey code in this case. As I mentioned the problem is in HeaderDelegate<MediaType> implementation present in CXF and an instance of this class is obtained and held in MediaType class itself (see [1] , lines 44-45) which is in JAX-RS API. One thing you can do is to set the RuntimeDelegate instance yourself (before any other Jersey code is invoked): RuntimeDelegate.setInstance( new com.sun.ws.rs.ext.RuntimeDelegateImpl()); [1] http://grepcode.com/file/repo1.maven.org/maven2/javax.ws.rs/jsr311-api/1.1.1/javax/ws/rs/core/MediaType.java#44
        Hide
        jaimegarza61 added a comment -

        I have realized that the only fix that could work for the Jersey team is for Jersey to produce headers in lower case.

        I have set the runtime delegate with META-INF property files, which is similar to the last suggestion, and I am just waiting to find the shoe drop on the cxf side, with some kind of CXF client issue. I will be trying to upgrade my cxf across the company. Thanks for the comments.

        Show
        jaimegarza61 added a comment - I have realized that the only fix that could work for the Jersey team is for Jersey to produce headers in lower case. I have set the runtime delegate with META-INF property files, which is similar to the last suggestion, and I am just waiting to find the shoe drop on the cxf side, with some kind of CXF client issue. I will be trying to upgrade my cxf across the company. Thanks for the comments.

          People

          • Assignee:
            Michal Gajdos
            Reporter:
            jaimegarza61
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: