2

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.

5
  • Take a look at flexjson.sourceforge.net. I know you might not be able to change from Gson but it does offer a very good alternative that seems better in some areas Commented Mar 2, 2011 at 8:22
  • I'm at the beggining of the project so I'd be able to swith if it really solves all problems I've already solved with gson. Now I have only one. Commented Mar 2, 2011 at 8:36
  • my advice is to make a test project and tryout both libraries side by side and see which one is easier/better. Also try and decouple your code from the actual java->json implementation so that later you can easily change it. Commented Mar 2, 2011 at 8:39
  • What I don't really like about flexjson that I have to include and exclude desired field myself. I want to have only one MessageConverter which would be able to do all work by itself. Gson aproach is better when you mark with the annotation @Expose all fields in an entity you want to be insluded. Commented Mar 2, 2011 at 8:41
  • Thank you a lot, Liviu T.! I do think it's a good advice :) but I decided to ask my colleagues who had already come across some pitfalls which json libraries have because as usually I don't have enough time for an investigation :) Commented Mar 2, 2011 at 8:43

1 Answer 1

1

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 
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer, Sean! As I mentioned before I don't like to be stick to the actual type like ypu mentioned Type type = new TypeToken<List<String>> because it means that every time I implement new generic type I have to implement new code for it. What I want is one implementation for all types is it possible. Anyway, thank you a lot! L.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.