1

In my Spring MVC Java application I'm using Jersey REST API. I am using Jackson for JSON processing. I added Genson to my project for filtering some fields for some classes. And I am trying to use Genson only for that and remaining I want to use Jackson.

But I am getting exception while using Jersey REST api as Jersey enabled Genson by default when the Jar is in the classpath (Got to know from this link).

Here is my code in connect to web service and get data and convert to String using Jackson

public String connect() throws Exception {
        Client client = Client.create();
        try {
            String auth = new String(Base64.encode(userName + COLON + password));
            WebResource webResource = client
                    .resource(webServiceUrl);
            ClientResponse response = webResource
                    .header(AUTHORIZATION, BASIC + auth).type(APPLICATION_JSON)
                    .accept(APPLICATION_JSON).get(ClientResponse.class);
            //code to check response status code.
                stringResponse = response.getEntity(String.class);

        } catch (ClientHandlerException e) {
            throw new Exception("Not a Valid Url.");
        } finally {
            client.destroy();
        }
        return stringResponse;
}

I'm getting following exception

javax.ws.rs.WebApplicationException: com.owlike.genson.JsonBindingException: Could not deserialize to type class java.lang.String
    at com.owlike.genson.ext.jaxrs.GensonJsonConverter.readFrom(GensonJsonConverter.java:130)
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:553)
    at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
    at com.myapp.WebHttpClient.connect(WebHttpClient.java:74)
    at com.myapp.connection.connectors.WebConnector.getData(WebConnector.java:39)
    at com.myapp.adapter.impl.SourceAdapter.getData(SourceAdapter.java:29)
    at com.myapp.service.impl.WebServiceImpl.adapter(WebServiceImpl.java:174)
    at com.myapp.service.impl.WebServiceImpl.connect(WebServiceImpl.java:107)
    ... 41 more
Caused by: com.owlike.genson.JsonBindingException: Could not deserialize to type class java.lang.String
    at com.owlike.genson.Genson.deserialize(Genson.java:398)
    at com.owlike.genson.ext.jaxrs.GensonJsonConverter.readFrom(GensonJsonConverter.java:128)
    ... 48 more
Caused by: com.owlike.genson.stream.JsonStreamException: Readen value can not be converted to String
    at com.owlike.genson.stream.JsonReader.valueAsString(JsonReader.java:200)
    at com.owlike.genson.convert.DefaultConverters$StringConverter.deserialize(DefaultConverters.java:364)
    at com.owlike.genson.convert.DefaultConverters$StringConverter.deserialize(DefaultConverters.java:351)
    at com.owlike.genson.convert.NullConverter$NullConverterWrapper.deserialize(NullConverter.java:56)
    at com.owlike.genson.Genson.deserialize(Genson.java:396)
    ... 49 more

Line 74 refers to stringResponse = response.getEntity(String.class);.

How to disable Genson for Jersey or How can I resolve this issue by using Genson?

Thanks

iCode
  • 8,892
  • 21
  • 57
  • 91
  • If you are ok with using genson always then you can directly deser to the type you want instead of getting the response as a string. – eugen Jan 20 '15 at 09:30
  • I want it as String. How can I get it? – iCode Jan 20 '15 at 10:06
  • If you still need to disable Genson in Jax-RS the new release includes this mechanism, please see my update. – eugen Apr 13 '15 at 12:16

2 Answers2

4

The up to date documentation of Genson is hosted on github http://owlike.github.io/genson/.

What actually happens

To me it is not clear where you want to use Genson and how. Are you using Genson for serialization only? Are you using it through jersey or directly?

When you do getEntity(String.class), Jersey asks Genson to deser the incoming json to a string. Note that in general json format does not allow strings as root values.

Solutions

  1. Upgrade to jersey 2.X (and latest Genson release), in the new Jersey version when you ask the input as a string it does not delegate to MessageBodyReader (correct behaviour IMO). Then you can use this string to deser to whatever type you want.

  2. Use getEntityInputStream method from ClientResponse to get the raw InputStream and convert it to a String.

  3. Another solution would be to override Gensons implementation of MessageBodyReader, to not handle deser to String.


Having multiple libs that handle JSON conversion at the same time does not sound right to me. Especially as both (Jackson and Genson) provide some similar features. I opened an issue allowing people to disable Genson in JAX-RS apps.

Update Genson 1.3 and up provide a system to disable Genson in a Jax-RS app.

eugen
  • 5,856
  • 2
  • 29
  • 26
  • 1
    I was only using Jackson. But in some cases I needed to remove fields from POJO while serializing. With Jackson It is more complex as it needs to add `@JsonFilter` annotation. If the annotation is present in a POJO class, there is problem while serializing in normal way with Jackson. So I'm using Genson. But that I'm directly using and not with Jersey. – iCode Jan 21 '15 at 07:16
  • And are there any features that you use with Jackson and don't exist with Genson? I recommend you to pick solution 1 and keep only one lib if it covers your use cases. Next release of Genson will include a system to disable it in jax rs apps. – eugen Jan 21 '15 at 07:41
  • I am trying to use Genson and remove Jackson. Thanks :) – iCode Jan 21 '15 at 09:18
  • `Use getEntityInputStream method from ClientResponse to get the raw InputStream and convert it to a String.` This saved me after a few hours of hopelessly bug hunting. Thanks! – GavinoGrifoni Nov 12 '15 at 15:19
0

Here's an example on solution 2...

Use getEntityInputStream method from ClientResponse to get the raw InputStream and convert it to a String:

private String responseString(ClientResponse response) {
    InputStream stream = response.getEntityInputStream();
    StringBuilder textBuilder = new StringBuilder();
    try (Reader reader = new BufferedReader(new InputStreamReader(stream, Charset.forName(StandardCharsets.UTF_8.name())))) {
        int c = 0;
        while ((c = reader.read()) != -1) {
            textBuilder.append((char) c);
        }
        return textBuilder.toString();
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
}
dvlcube
  • 1,117
  • 1
  • 12
  • 20