7 Replies Latest reply: May 8, 2013 12:00 AM by r035198x RSS

    JAXB Based JSON support not working with Jersey JAX-RS

    873896
      Do I make something wrong using JAXB based JSON support with the Jersey 1.17 Client API?
      The code below delivers
      415
      [text/html;charset=utf-8]
      Mai 01, 2013 8:23:30 AM com.sun.jersey.api.client.ClientResponse getEntity
      SEVERE: A message body reader for Java class client.Pair, and Java type class client.Pair, and MIME media type text/html; charset=utf-8 was not found
      Mai 01, 2013 8:23:30 AM com.sun.jersey.api.client.ClientResponse getEntity
      SEVERE: The registered message body readers compatible with the MIME media type are:
      */* ->
      com.sun.jersey.core.impl.provider.entity.FormProvider
      com.sun.jersey.core.impl.provider.entity.StringProvider
      com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
      com.sun.jersey.core.impl.provider.entity.FileProvider
      com.sun.jersey.core.impl.provider.entity.InputStreamProvider
      com.sun.jersey.core.impl.provider.entity.DataSourceProvider
      com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
      com.sun.jersey.core.impl.provider.entity.ReaderProvider
      com.sun.jersey.core.impl.provider.entity.DocumentProvider
      com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
      com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
      com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
      com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
      com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$General
      com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$General
      com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
      com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
      com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
      com.sun.jersey.core.impl.provider.entity.EntityHolderReader
      com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
      com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
      com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy

      Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class client.Pair, and Java type class client.Pair, and MIME media type text/html; charset=utf-8 was not found
           at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:561)
           at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:517)
           at client.ComputeConcat.main(ComputeConcat.java:39)



      package server;

      import javax.ws.rs.Consumes;
      import javax.ws.rs.POST;
      import javax.ws.rs.Path;
      import javax.ws.rs.Produces;
      import javax.ws.rs.core.MediaType;

      /**
      *
      * calling with data as JSON serialization
      * $ curl -X POST --data-binary "{ \"first\":\"Hello, \", \"second\":\"World.\" }" \
      * -H "Content-Type: application/json" -H "Accept: application/json" \
      * --user exampleuser:changeit \
      * http://localhost:8080/JAXRSServer/rs/concatEngine/concat
      * delivers
      * { "first":"Hello, World." }
      */
      @Path("/concatEngine")
      public class ConcatEngine {
      @POST
      @Path("/concat")
      // MediaType.APPLICATION_XML,
      @Consumes({MediaType.APPLICATION_JSON})
      @Produces({MediaType.APPLICATION_JSON})
      public Pair concat(Pair data) {
      Pair res = new Pair();
      res.setFirst(data.getFirst() + data.getSecond());
      return res;
      }
      }



      package server;

      import javax.xml.bind.annotation.XmlAccessType;
      import javax.xml.bind.annotation.XmlAccessorType;
      import javax.xml.bind.annotation.XmlRootElement;

      @XmlRootElement
      @XmlAccessorType(XmlAccessType.PROPERTY)
      public class Pair {
      protected String first;
      protected String second;

      public Pair() {
      }

      public String getFirst() {
      return first;
      }

      public void setFirst(String first) {
      this.first = first;
      }

      public String getSecond() {
      return second;
      }

      public void setSecond(String second) {
      this.second = second;
      }
      }



      package client;

      import javax.ws.rs.core.MediaType;

      import com.sun.jersey.api.client.Client;
      import com.sun.jersey.api.client.ClientResponse;
      import com.sun.jersey.api.client.WebResource;
      import com.sun.jersey.api.client.config.ClientConfig;
      import com.sun.jersey.api.client.config.DefaultClientConfig;

      public class ComputeConcat {

      private static WebResource getHttpResource() {
      ClientConfig config = new DefaultClientConfig();
      // config.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
      // config.getClasses().add(JSONRootElementProvider.class);
      Client client = Client.create(config);
      return client.resource(
      "http://localhost:8080/JAXRSServer/rs/concatEngine/concat");
      }


      public static void main(String[] args) {
      Pair pair = new Pair();
      pair.setFirst("Hello, "); pair.setSecond("World!");

      WebResource resource = getHttpResource();

      // resource.accept(MediaType.APPLICATION_XML);
      resource.accept(MediaType.APPLICATION_JSON);
      resource.type(MediaType.APPLICATION_JSON);
      // resource.header("content-type", MediaType.APPLICATION_JSON);

      ClientResponse response = resource.post(ClientResponse.class, pair);
      System.out.println(response.getStatus());
      System.out.println(response.getHeaders().get("Content-Type"));
      Pair res = response.getEntity(Pair.class);
      System.out.println(res.getFirst());
      }

      }


      My web.xml (under Tomcat) if that should be of interest:

      <?xml version="1.0" encoding="UTF-8"?>
      <web-app id="WebApp_ID" version="3.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

      <display-name>JAXRSServer</display-name>

      <servlet>
      <servlet-name>Jersey REST Service</servlet-name>
      <servlet-class>
      com.sun.jersey.spi.container.servlet.ServletContainer
      </servlet-class>
      <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>server</param-value>
      </init-param>
      <!-- init-param>
      <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
      <param-value>true</param-value>
      </init-param -->
      <load-on-startup>1</load-on-startup>
      </servlet>
      <servlet-mapping>
      <servlet-name>Jersey REST Service</servlet-name>
      <url-pattern>/rs/*</url-pattern>
      </servlet-mapping>
      </web-app>



      If changing @Consumes({MediaType.APPLICATION_JSON}) to @Consumes({MediaType.APPLICATION_XML}) for the concat method, then the code operates. However, the input pair is sent as XML and not as JSON serialization. It seems like the Jersy Client does not automatically serialize the pair object to JSON but only to XML, although imho it should.

      Any ideas? Thank you!
        • 1. Re: JAXB Based JSON support not working with Jersey JAX-RS
          gimbal2
          The error seems really off to me.
          A message body reader for Java class client.Pair, and Java type class client.Pair, and MIME media type text/html; charset=utf-8
          Jersey seems to be either expecting or getting HTML content as a response. I'm wondering if the JAX-RS service you are invoking is actually doing what you are thinking it should be doing.
          • 2. Re: JAXB Based JSON support not working with Jersey JAX-RS
            873896
            Jersey seems to be either expecting or getting HTML content as a response. I'm wondering if
            the JAX-RS service you are invoking is actually doing what you are thinking it should be doing
            Please note that the first 2 lines are output of my client programm. The http error code is 415. That means that only the error message is text/html. If only using MediaType.APPLICATION_XML on the various occurences instead of ...JSON the program works perfect! Also in its current form using curl as indicated in the comment of the server class, it works with JSON perfectly.

            The problem is imho the client of Jersey, which does not perfomr the right (JSON) serialization.
            • 3. Re: JAXB Based JSON support not working with Jersey JAX-RS
              gimbal2
              de-serialization since the crash seems to happen in getEntity(). The post request you send seems to work just fine, so the serialization part must work.

              I have no clue what could be wrong. If you get no other responses I would try the jersey user mailing list:

              https://java.net/projects/jersey/lists
              • 4. Re: JAXB Based JSON support not working with Jersey JAX-RS
                873896
                Posted on the user list and created an entry to the issues database of Jersey:

                https://java.net/jira/browse/JERSEY-1879

                However, I neither way I get some response. Seems that either nobody cares or that my question is somehow ridiculous. Btw. I am not the only one:

                http://stackoverflow.com/questions/12630917/posting-json-via-jersey

                The hints provided in this posting do not operate, or at least I cannot Interpret them correctly.
                • 5. Re: JAXB Based JSON support not working with Jersey JAX-RS
                  873896
                  I found the error:

                  resource.type(MediaType.APPLICATION_JSON);
                  resource.accept(MediaType.APPLICATION_JSON);
                  ClientResponse response = resource.post(ClientResponse.class, pair);

                  The methods of WebResource (ie post) always create new WebResource.Builder objects. That is setting the type to MediaType.APPLICATION_JSON is done in an object for the garbage collector, and not the one which issues
                  post.

                  The following code operates.

                  WebResource resource = getHttpResource();
                  WebResource.Builder builder = resource.getRequestBuilder();
                  builder.accept(MediaType.APPLICATION_JSON_TYPE);
                  builder.type(MediaType.APPLICATION_JSON_TYPE);
                  ClientResponse response = builder.post(ClientResponse.class, pair);

                  However, this behavior is poorly documented and contrintuitive. For chaining/fluent API the passed objects better should be changed and a reference to them returned.

                  Hower, many thanks for your help.
                  • 6. Re: JAXB Based JSON support not working with Jersey JAX-RS
                    gimbal2
                    This strikes me as something very curious and potentially wrong. I would expect that this internally constructed builder would adopt the resource settings and apparently you have now proven this is not the case. At least not in the version of Jersey you're using. On the other hand I have not worked with the JAX-RS API long enough yet to fully understand its inner workings, perhaps I'm just making false claims.

                    Nice catch by the way, and thanks for posting back a solution.
                    • 7. Re: JAXB Based JSON support not working with Jersey JAX-RS
                      r035198x
                      The builder pattern is used here so you must use
                      response = resource.type(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).post(ClientResponse.class, pair);
                      Edited by: r035198x on May 8, 2013 7:00 AM