dev2018. 2. 13. 17:57

gson TypeToken 사용

clasa Box<T> {
    public T item;
}
class Doll {
    public int price;
    public String concept;
}
class Food {
    public int price;
    public int sugar;
}
...
class Test {
    @Test
    public void test() throws Exception {
        // json : {"item":{"price":800,"concept":"party"}}
        Gson gson = new Gson();

        // 이건 아주 잘 됨.
        Box<Doll> box = gson.fromJson(json, new TypeToken<Box<Doll>>(){}.getType());
        Assert.assertEquals("party", box.item.concept);
    }
}

예를들어 위와 같은 상황이 있다.
Box 클래스에서 Item 클래스를 프로퍼티로 포함하고 있는 구조인데,
json 파싱을 통해 Box 클래스의 객체로 받고자 한다.

의도치 않게 다양한 삽질을 하게 되었는데 결과만 공유.

되는거 - TypeToken.getParameterized 활용

private <T> T convert(String json, Class<T> clazz) {
    Box<T> response = gson.fromJson(json, TypeToken.getParameterized(Box.class, clazz).getType());
    return response.item;
}
  • 제너릭 타입을 많이 혹은 복잡하게 갖는 클래스라면, getParameterized 활용을 검토해보는 것도 좋을 것 같다.

망한거 - new TypeToken<A<B>>

  • 실패 코드 1
// 이건 잘 되는 것 같지만..
// response.item 은 com.google.gson.internal.LinkedTreeMap 객체로 생성된다.
// 즉, TypeToken<Box<T>> 에서 T 를 제대로 넘기지 못하는 듯.
private <T> Box<T> convert(String json) {
    Box<T> response = gson.fromJson(json, new TypeToken<Box<T>>(){}.getType());
    return response;
}
  • 실패 코드 2
private <T> T convert(String json) {
    Box<T> response = gson.fromJson(json, new TypeToken<Box<T>>(){}.getType());
    return response.item;   // 여전히 com.google.gson.internal.LinkedTreeMap 타입임.
}
...

@Test
public void test() throws Exception {
    ...
    Doll doll = convert(json);  // 실패 발생!
    ...
}
  • 오류
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.kong.Doll