Larisa
Larisa

Reputation: 73

GSON and Generic types

I've come across a problem of using Gson library and generic types(my types and collections). However they have an answer how to solve this problem, I don't think it's appropriate to write a specific message converter for the every type I've already implemented and I'll implement.

What I did is:

Implemented my own message converter:

public class SuperHttpMessageConverter extends AbstractHttpMessageConverter<Object> {

private final Charset charset;
private final Gson gson;

public CostomHttpMC_1(MediaType mediaType, String charset) {
    super(mediaType);
    this.charset = Charset.forName(charset);
    gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
}

@Override
protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
    String jsonString = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
    return gson.fromJson(jsonString, clazz);
}

@Override
protected Long getContentLength(Object obj, MediaType contentType) {
    try {
        String jsonString = gson.toJson(obj);
        return (long) jsonString.getBytes(charset.name()).length;
    } catch (UnsupportedEncodingException ex) {
        throw new InternalError(ex.getMessage());
    }
}

@Override
protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException {
    String jsonString = gson.toJson(obj);
    FileCopyUtils.copy(jsonString, new OutputStreamWriter(outputMessage.getBody(), charset));
}

@Override
public boolean supports(Class<?> clazz) {
    return true;
}

}

It works well until I try to send a collection like List<String> or some Type<T>.

Gson has the solutions here: http://sites.google.com/site/gson/gson-user-guide

Also I tried the json-lib library yesterday. What I don't like about it is in-depth scanning of all objects which I have in the hierarchy. I tried to change the cycle detection strategy from CycleDetectionStrategy.STRICT to CycleDetectionStrategy.LENIENT, it didn't help at all!

    @Override
protected void writeInternal(Object obj, HttpOutputMessage outputMessage) throws IOException {
    JsonConfig jsonConfig = new JsonConfig();  
    jsonConfig.setCycleDetectionStrategy(CycleDetectionStrategy.LENIENT);
    String jsonString = JSONObject.fromObject( obj ).toString();
    FileCopyUtils.copy(jsonString, new OutputStreamWriter(outputMessage.getBody(), charset));
}

Finally, a work-around for the generic collection's problem was found out: changing from ArrayList to simple array helps to do serialization and deserialization. To be more specific you have to do it in a web-service, which you use in an application.

   @RequestMapping(value = "/country/info/{code}")
public void info(@PathVariable("code") String code, Model model) {

//list
    StuffImpl[] stuffList= new StuffImpl[0]; <-- this is the array I used!
stuffList= restTemplate.getForObject("http://localhost:8084/yourApp/restService/stuff", stuffList.getClass());
model.addAttribute("stuffList", stuffList);
}

So this approach is working good.

I failed to found out what a solution for generic type is. I really do hate an idea to write a new converter every time I implement a new generic type.

If you know any possible solution I'd appreciate your help a lot!

I'd be on the cloud nine if anyone could help me :)

L.

Upvotes: 2

Views: 3428

Answers (1)

FrVaBe
FrVaBe

Reputation: 49341

There are some methods where you can pass java.lang.reflect.Type. These methods are useful if the specified object is a generic type, e.g.:

Gson gson = new GsonBuilder().create();

List<String> names = new ArrayList<String>();
names.add("Foo");
names.add("Bar");

// marshal
String jsonLiteral = gson.toJson(names);
System.out.println(jsonLiteral);

// unmarshal
List<String> names2;
Type type = new TypeToken<List<String>>() {
}.getType();
names2 = gson.fromJson(jsonLiteral, type);
System.out.println(names2.get(0));
System.out.println(names2.get(1));

This will output:

["Foo","Bar"]
Foo
Bar

Upvotes: 1

Related Questions