tl;dnrUse Jackson, not Gson. Use this article as a reference for basic features.Part 1 of this short series of articles ended with section 5.3 of the Gson user guide, titled "Nested Classes (including Inner Classes)". This second part continues with section 5.4 on "Array Examples", and ends with section 5.7 on "Serializing and Deserializing Collection with Objects of Arbitrary Types". Part 3 will continue with section 5.8 on "Built-in Serializers and Deserializers". | Link To This Articlehttp://goo.gl/qkceb |
See part 6 of this series for a complete listing of and links to the various sections of this Gson user guide review.
For cross reference, readers will likely find it useful to also have the Gson user guide open in another browser window. (An archive of the Gson user guide as of 2011.06.26 is available at https://sites.google.com/site/programmerbruce/downloads/Gson_User_Guide_2011.06.26.zip.)
This information is based on Gson release 1.7.1 and Jackson release 1.8.2.
The Gson User Guide Walk-through Continued...
Array Examples
The Gson Code: See relevant section in the Gson user guide.
The comparable Jackson Code:
ObjectMapper mapper = new ObjectMapper();Comparison Rating: COMPARABLE
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};
// (Serialization)
System.out.println(mapper.writeValueAsString(ints));
// output: [1,2,3,4,5]
System.out.println(mapper.writeValueAsString(strings));
// output: ["abc","def","ghi"]
// (Deserialization)
int[] ints2 = mapper.readValue("[1,2,3,4,5]", int[].class);
System.out.println(Arrays.toString(ints2));
// output: [1, 2, 3, 4, 5]
Additional Section Notes: This Gson user guide section ends with the statement, "We also support multi-dimensional arrays, with arbitrarily complex element types." This is unfortunately not an entirely correct statement, if it is applied to the context of data-binding, in which it was presented. The statement should be modified to read, "We also provide limited support for multi-dimensional arrays, with limited support for arbitrarily complex element types."
Examples to support this include the following.
Gson gson = new Gson();Additional Code Notes:
ObjectMapper mapper = new ObjectMapper();
// 1-dimension array with varying primitive type elements
// input: ["abc",42]
String json1 = "[\"abc\",42]";
Object[] things1a = gson.fromJson(json1, Object[].class);
System.out.println(Arrays.toString(things1a));
// output: [abc, 42]
Object[] things1b = mapper.readValue(json1, Object[].class);
System.out.println(Arrays.toString(things1b));
// output: [abc, 42]
// 2x2 array with varying primitive type elements
// input: [["abc",42],["def",43]]
String json2 = "[[\"abc\",42],[\"def\",43]]";
Object[][] things2a1 = gson.fromJson(json2, Object[][].class);
System.out.println(Arrays.toString(things2a1[0]));
// output: [abc, 42]
System.out.println(Arrays.toString(things2a1[1]));
// output: [def, 43]
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target is not a primitive: ["abc",42]
// Object[] things2a2 = gson.fromJson(json2, Object[].class);
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target is not a primitive: [["abc",42],["def",43]]
// Object things2a3 = gson.fromJson(json2, Object.class);
Object[][] things2b1 =
mapper.readValue(json2, Object[][].class);
System.out.println(Arrays.toString(things2b1[0]));
// output: [abc, 42]
System.out.println(Arrays.toString(things2b1[1]));
// output: [def, 43]
Object[] things2b2 = mapper.readValue(json2, Object[].class);
System.out.println(Arrays.toString(things2b2));
// output: [[abc, 42], [def, 43]]
System.out.println(things2b2[0].getClass());
// output: class java.util.ArrayList
Object things2b3 = mapper.readValue(json2, Object.class);
System.out.println(things2b3);
// output: [[abc, 42], [def, 43]]
System.out.println(things2b3.getClass());
// output: class java.util.ArrayList
// "uneven" multi-dimensional array
// input: [["abc",[42,24]],["def",[43,34]]]
String json3 = "[[\"abc\",[42,24]],[\"def\",[43,34]]]";
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target is not a primitive: [42,24]
// Object[][] things3a1 =
// gson.fromJson(json3, Object[][].class);
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target is not a primitive: ["abc",[42,24]]
// Object[] things3a2 = gson.fromJson(json3, Object[].class);
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target is not a primitive:
// [["abc",[42,24]],["def",[43,34]]]
// Object things3a3 = gson.fromJson(json3, Object.class);
// throws RuntimeException
// Object[][][] things3a4 =
// gson.fromJson(json3, Object[][][].class);
Object[][] things3b1 =
mapper.readValue(json3, Object[][].class);
System.out.println(things3b1[0][0].getClass());
// output: class java.lang.String
System.out.println(things3b1[0][1].getClass());
// output: class java.util.ArrayList
System.out.println(Arrays.toString(things3b1[0]));
// output: [abc, [42, 24]]
System.out.println(Arrays.toString(things3b1[1]));
// output: [def, [43, 34]]
Object[] things3b2 = mapper.readValue(json3, Object[].class);
System.out.println(Arrays.toString(things3b2));
// output: [[abc, [42, 24]], [def, [43, 34]]]
Object things3b3 = mapper.readValue(json3, Object.class);
System.out.println(things3b3);
// [[abc, [42, 24]], [def, [43, 34]]]
mapper.configure(
DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
true);
Object[][][] things3b4 =
mapper.readValue(json3, Object[][][].class);
System.out.println(things3b4.length); // 2
System.out.println(things3b4[0].length); // 2
System.out.println(things3b4[0][0].length); // 1
System.out.println(things3b4[0][1].length); // 2
System.out.println(things3b4[1].length); // 2
System.out.println(things3b4[1][0].length); // 1
System.out.println(things3b4[1][1].length); // 2
System.out.println(things3b4[0][0][0].getClass());
// output: class java.lang.String
System.out.println(things3b4[0][1][0].getClass());
// output: class java.lang.Integer
System.out.println(things3b4[0][1][1].getClass());
// output: class java.lang.Integer
for (int i = 0; i < things3b4.length; i++)
for (int ii = 0; ii < things3b4[i].length; ii++)
for (int iii = 0; iii < things3b4[i][ii].length; iii++)
System.out.print(things3b4[i][ii][iii] + " ");
// output: abc 42 24 def 43 34
System.out.println();
mapper = new ObjectMapper();
// input: [42,{"one":1}]
String json4 = "[42,{\"one\":1}]";
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target is not a primitive: [42,{"one":1}]
// Object things4a1 = gson.fromJson(json4, Object.class);
// throws JsonParseException, complaining:
// Type information is unavailable,
// and the target object is not a primitive: {"one":1}
// Object[] things4a2 = gson.fromJson(json4, Object[].class);
Object things4b1 = mapper.readValue(json4, Object.class);
System.out.println(things4b1);
// output: [42, {one=1}]
System.out.println(things4b1.getClass());
// output: class java.util.ArrayList
List things4b1List = (List) things4b1;
System.out.println(things4b1List.size()); // 2
System.out.println(things4b1List.get(0).getClass());
// output: class java.lang.Integer
System.out.println(things4b1List.get(1).getClass());
// output: class java.util.LinkedHashMap
Object[] things4b2 = mapper.readValue(json4, Object[].class);
System.out.println(Arrays.toString(things4b2));
// output: [42, {one=1}]
System.out.println(things4b2[0].getClass());
// class java.lang.Integer
System.out.println(things4b2[1].getClass());
// class java.util.LinkedHashMap
- These are not a contrived examples. The structures are based on real-world JSON.
- How to implement custom deserialization processing with Gson to handle these examples is briefly described in the "Serializing and Deserializing Collection with Objects of Arbitrary Types" section of the Gson user guide.
Comparison Ratings:
- +1 Jackson for significantly more complete data-binding support of multi-dimensional arrays
- +1 Jackson for significantly more complete data-binding support of arbitrarily complex array element types
Collections Examples
The Gson Code: See relevant section in the Gson user guide.
The comparable Jackson Code:
ObjectMapper mapper = new ObjectMapper();Code Notes: As demonstrated, Jackson offers two ways to solve the deserialization to generic types problem.
Collection<Integer> ints = Arrays.asList(1,2,3,4,5);
// (Serialization)
String json = mapper.writeValueAsString(ints);
System.out.println(json); // [1,2,3,4,5]
// (Deserialization)
TypeReference collectionType =
new TypeReference<Collection<Integer>>(){};
Collection<Integer> ints2 =
mapper.readValue(json, collectionType);
System.out.println(ints2); // [1, 2, 3, 4, 5]
CollectionType collectionType2 =
TypeFactory.defaultInstance().constructCollectionType(
Collection.class, Integer.class);
Collection<Integer> ints3 =
mapper.readValue(json, collectionType2);
System.out.println(ints3); // [1, 2, 3, 4, 5]
Comparison Rating: COMPARABLE
Collections Limitations
Concerning the Gson user guide statements on collections limitations, including that Gson "[c]an serialize [a] collection of arbitrary objects but can not deserialize from it," note that Jackson is not similarly deficient, provided that polymorphic type information is available in the JSON and that other necessary configurations are made. For examples of deserializing JSON into polymorphic structures with Jackson, see http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html.
Comparison Rating: +1 Jackson for built-in polymorphic deserialization capability****
****The next release of Gson is planned to included some built-in support for polymorphic deserialization, as described in issue 231.
Serializing and Deserializing Generic Types
The Gson Code: See relevant section in the Gson user guide.
Note that the guide's statement that
gson.toJson(myStrings);
will cause a runtime exception is wrong, depending on the actual type of the list instance. The following demonstrates this point using an ArrayList.List<String> myStrings = new ArrayList<String>();Additional Notes:
myStrings.add("one");
myStrings.add("two");
myStrings.add("three");
Gson gson = new Gson();
String json1 = gson.toJson(myStrings);
System.out.println(json1);
// output: ["one","two","three"]
List<String> myStrings2 =
gson.fromJson(json1, myStrings.getClass());
System.out.println(myStrings2);
// output: [java.lang.Object@27ce2dd4,
// java.lang.Object@5122cdb6, java.lang.Object@43ef9157]
Object o1 = myStrings2.get(0);
System.out.println(o1.getClass());
// class java.lang.Object
ObjectMapper mapper = new ObjectMapper();
String json2 = mapper.writeValueAsString(myStrings);
System.out.println(json2);
// output: ["one","two","three"]
List<String> myStrings3 =
mapper.readValue(json2, myStrings.getClass());
System.out.println(myStrings3);
// output: [one, two, three]
Object o2 = myStrings3.get(0);
System.out.println(o2.getClass());
// output: class java.lang.String
- Note that Gson populated the deserialized list with useless Object instances, retaining none of the data from the JSON input. This is a problem that Gson also has with non-generic Map collections. (See issue 325 for details.)
- The use of a TypeToken to resolve this issue, and the Jackson counter parts, were demonstrated in the Collections Examples section.
Comparison Rating: +1 Jackson for significantly better support of deserializing to non-generic collections
Serializing and Deserializing Collection with Objects of Arbitrary Types
The Gson Code: See relevant section in the Gson user guide.
Differing from Gson, Jackson can deserialize the example JSON to a collection, without generic type information, and without implementing any of the suggested custom processing solutions.
The Jackson Code:
ObjectMapper mapper = new ObjectMapper();Comparison Ratings:
Collection collection = new ArrayList();
collection.add("hello");
collection.add(5);
collection.add(new Event("GREETINGS", "guest"));
System.out.println(mapper.writeValueAsString(collection));
// output: ["hello",5,{"name":"GREETINGS","source":"guest"}]
// input: ["hello",5,{"name":"GREETINGS","source":"guest"}]
String json =
"[\"hello\",5,{\"name\":\"GREETINGS\",\"source\":\"guest\"}]";
Collection things = mapper.readValue(json, Collection.class);
System.out.println(things);
// output: [hello, 5, {name=GREETINGS, source=guest}]
- COMPARABLE for similar support to serialize collections with arbitrary types
- +1 Jackson for significantly better support of deserializing to non-generic collections
Continue to part 3...
No comments:
Post a Comment