Java & Android
Gson Basics
그레이트쪼
2017. 1. 31. 20:23
Overview
- Google에서 내부용으로 사용하려고 만든 Json, Java object간 변환 도구
- Gson class로부터 시작한다. (여러 번 재사용 가능한 객체)
- JSON 라이브러리 밴치마킹
http://djkeh.github.io/articles/The-fastest-way-to-parse-json-data-to-java-kor/
예제를 통해 case by case 사용법을 익혀보자.
- 기본형
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // Serialization Gson gson = new Gson(); gson.toJson(1); // ==> 1 gson.toJson("abcd"); // ==> "abcd" gson.toJson(new Long(10)); // ==> 10 int[] values = { 1 }; gson.toJson(values); // ==> [1] // Deserialization int one = gson.fromJson("1", int.class); Integer one = gson.fromJson("1", Integer.class); Long one = gson.fromJson("1", Long.class); Boolean false = gson.fromJson("false", Boolean.class); String str = gson.fromJson("\"abc\"", String.class); String[] anotherStr = gson.fromJson("[\"abc\"]", String[].class); |
- Object형
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | class BagOfPrimitives { private int value1 = 1; private String value2 = "abc"; private transient int value3 = 3; BagOfPrimitives() { // no-args constructor } } // Serialization BagOfPrimitives obj = new BagOfPrimitives(); Gson gson = new Gson(); String json = gson.toJson(obj); // ==> json is {"value1":1,"value2":"abc"} // Deserialization BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class); // ==> obj2 is just like obj |
- private field도 된다. (annotation이 전혀 필요 없다)
- transient 키워드가 있는 경우 제외한다. (transient가 serialization을 막는 키워드이므로)
- Serialize할 때 null 값들은 skip 된다. 반대로 JSON에서 missing entry는 deserialize할 때 null로 대입된다.
- Inner class에 있는 outer class 대응 field, anonymous class, local class는 무시된다.
- Nested class
- 일반적으로 nested inner class도 다 처리할 수 있는데 아래의 경우와 같이 inner class가 param이 없는 기본 생성자를 가지고 있을 경우 serialize가 안된다. (이유에 대한 설명이 이해 안됨)
1 2 3 4 5 6 7 8 9 10 11 12 | public class A { public String a; class B { public String b; public B() { // No args constructor for B } } } |
- 이 경우 inner class 앞에 static 키워드를 붙여라. (아니면 특별한 instance creator를 정의하는 방법도 있는데 추천하진 않는다고 되어 있음)
- Array
1 2 3 4 5 6 7 8 9 10 11 | Gson gson = new Gson(); int[] ints = {1, 2, 3, 4, 5}; String[] strings = {"abc", "def", "ghi"}; // Serialization gson.toJson(ints); // ==> [1,2,3,4,5] gson.toJson(strings); // ==> ["abc", "def", "ghi"] // Deserialization int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); // ==> ints2 will be same as ints |
- Multi-dimension도 가능하다.
- Collections
1 2 3 4 5 6 7 8 9 10 | Gson gson = new Gson(); Collection<Integer> ints = Lists.immutableList(1,2,3,4,5); // Serialization String json = gson.toJson(ints); // ==> json is [1,2,3,4,5] // Deserialization Type collectionType = new TypeToken<Collection<Integer>>(){}.getType(); Collection<Integer> ints2 = gson.fromJson(json, collectionType); // ==> ints2 is same as ints |
- Gson은 임의의 object에 대한 collection을 serialize할 수는 있지만 deserialize할 수는 없다. 따라서 위의 예제와 같이 Generic type을 사용한 collection에 대해 사용하여야 한다.
- 만약 임의의 Object에 대한 collection을 사용할 필요가 있다면 Gson parser API (low-level streaming parser / DOM parser를 제공)를 사용하든지, Collection.class를 위한 type adapter를 등록하든지, MyCollectionMemberType을 위한 adapter를 등록해서 Collection<MyCollectionMemberType>의 fromJson()을 사용하는 방법이 있다. (자세한 건 공식 가이드를 참고해라)
- Generic
- 아래와 같이 코드를 짜면 안된다.
1 2 3 4 5 6 7 8 | class Foo<T> { T value; } Gson gson = new Gson(); Foo<Bar> foo = new Foo<Bar>(); gson.toJson(foo); // May not serialize foo.value correctly gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar |
- Gson은 그냥 Foo.class라고 인식해버린다. 따라서 아래와 같이 작성해야 한다.
1 2 3 4 | Type fooType = new TypeToken<Foo<Bar>>() {}.getType(); gson.toJson(foo, fooType); gson.fromJson(json, fooType); |
- Custom serializer and deserializer
- Custom serializer/deserializer를 지원하는데 특히나 library class (예를 들어, DateTime)들을 다룰 때 유용하다. Gson은 이를 위해 Json Serializers, Json Deserializers, Instance Creators 인터페이스를 지원한다. 아래와 같이 인터페이스를 구현한 custom class들을 GsonBuilder에 등록하면 된다.
1 2 3 4 5 | GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter()); gson.registerTypeAdapter(MyType.class, new MySerializer()); gson.registerTypeAdapter(MyType.class, new MyDeserializer()); gson.registerTypeAdapter(MyType.class, new MyInstanceCreator()); |
- 아래는 DateTime에 대한 Serializer의 작성 예제이다. JsonSerializer를 implements 하였다.
1 2 3 4 5 | private class DateTimeSerializer implements JsonSerializer<DateTime> { public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } } |
- 아래는 DateTime에 대한 Deserializer의 작성 예제이다. JsonDeserializer를 implements 하였다.
1 2 3 4 5 6 | private class DateTimeDeserializer implements JsonDeserializer<DateTime> { public DateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new DateTime(json.getAsJsonPrimitive().getAsString()); } } |
- DateTime같은 concrete class 뿐 아니라 generic class에 대해서도 JsonSerializer, JsonDeserializer 등록 가능하다 (자세한 것은 역시 user manual 참조)
- Instance Creators의 경우 기본 생성자 (no-args constructor)가 있거나 deserializer가 등록되어 있으면 만들 필요는 없다. 아래은 예제이다.
1 2 3 4 5 | private class MoneyInstanceCreator implements InstanceCreator<Money> { public Money createInstance(Type type) { return new Money("1000000", CurrencyCode.USD); } } |