From c6bef300579d96fe90e5be8240ee595ae8da66f1 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Mon, 11 Jul 2011 22:26:53 +0000 Subject: [PATCH] Array support. --- .../google/gson/mini/ArrayTypeAdapter.java | 92 +++++++++++++++++++ .../gson/mini/CollectionTypeAdapter.java | 2 +- .../java/com/google/gson/mini/MiniGson.java | 3 +- ....java => StringToValueMapTypeAdapter.java} | 19 ++-- .../com/google/gson/mini/MiniGsonTest.java | 24 +++++ 5 files changed, 125 insertions(+), 15 deletions(-) create mode 100644 extras/src/main/java/com/google/gson/mini/ArrayTypeAdapter.java rename extras/src/main/java/com/google/gson/mini/{MapTypeAdapter.java => StringToValueMapTypeAdapter.java} (86%) diff --git a/extras/src/main/java/com/google/gson/mini/ArrayTypeAdapter.java b/extras/src/main/java/com/google/gson/mini/ArrayTypeAdapter.java new file mode 100644 index 00000000..13fe79b0 --- /dev/null +++ b/extras/src/main/java/com/google/gson/mini/ArrayTypeAdapter.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.gson.mini; + +import com.google.gson.internal.$Gson$Types; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; + +/** + * Adapt an array of objects. + */ +final class ArrayTypeAdapter extends TypeAdapter { + public static final Factory FACTORY = new Factory() { + public TypeAdapter create(MiniGson context, TypeToken typeToken) { + Type type = typeToken.getType(); + if (!(type instanceof GenericArrayType || type instanceof Class && ((Class) type).isArray())) { + return null; + } + + Type componentType = $Gson$Types.getArrayComponentType(type); + TypeAdapter componentTypeAdapter = context.getAdapter(TypeToken.get(componentType)); + @SuppressWarnings("unchecked") // create() doesn't define a type parameter + TypeAdapter result = new ArrayTypeAdapter( + componentTypeAdapter, $Gson$Types.getRawType(componentType)); + return result; + } + }; + + private final Class componentType; + private final TypeAdapter componentTypeAdapter; + + public ArrayTypeAdapter(TypeAdapter componentTypeAdapter, Class componentType) { + this.componentTypeAdapter = componentTypeAdapter; + this.componentType = componentType; + } + + public Object read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); // TODO: does this belong here? + return null; + } + + List list = new ArrayList(); + reader.beginArray(); + while (reader.hasNext()) { + E instance = componentTypeAdapter.read(reader); + list.add(instance); + } + reader.endArray(); + Object array = Array.newInstance(componentType, list.size()); + for (int i = 0; i < list.size(); i++) { + Array.set(array, i, list.get(i)); + } + return array; + } + + @Override public void write(JsonWriter writer, Object array) throws IOException { + if (array == null) { + writer.nullValue(); // TODO: better policy here? + return; + } + + writer.beginArray(); + for (int i = 0, length = Array.getLength(array); i < length; i++) { + final E value = (E) Array.get(array, i); + componentTypeAdapter.write(writer, value); + } + writer.endArray(); + } +} diff --git a/extras/src/main/java/com/google/gson/mini/CollectionTypeAdapter.java b/extras/src/main/java/com/google/gson/mini/CollectionTypeAdapter.java index 79973b35..048667b9 100644 --- a/extras/src/main/java/com/google/gson/mini/CollectionTypeAdapter.java +++ b/extras/src/main/java/com/google/gson/mini/CollectionTypeAdapter.java @@ -67,7 +67,7 @@ final class CollectionTypeAdapter extends TypeAdapter> { return null; } - @SuppressWarnings("unchecked") // we don't define a type parameter for the element type + @SuppressWarnings("unchecked") // create() doesn't define a type parameter TypeAdapter result = new CollectionTypeAdapter(elementTypeAdapter, constructor); return result; } diff --git a/extras/src/main/java/com/google/gson/mini/MiniGson.java b/extras/src/main/java/com/google/gson/mini/MiniGson.java index 2fa98ce0..ee7bae1b 100644 --- a/extras/src/main/java/com/google/gson/mini/MiniGson.java +++ b/extras/src/main/java/com/google/gson/mini/MiniGson.java @@ -39,7 +39,8 @@ public final class MiniGson { factories.add(TypeAdapters.STRING_FACTORY); factories.add(ReflectiveTypeAdapter.FACTORY); factories.add(CollectionTypeAdapter.FACTORY); - factories.add(MapTypeAdapter.FACTORY); + factories.add(StringToValueMapTypeAdapter.FACTORY); + factories.add(ArrayTypeAdapter.FACTORY); this.factories = Collections.unmodifiableList(factories); } diff --git a/extras/src/main/java/com/google/gson/mini/MapTypeAdapter.java b/extras/src/main/java/com/google/gson/mini/StringToValueMapTypeAdapter.java similarity index 86% rename from extras/src/main/java/com/google/gson/mini/MapTypeAdapter.java rename to extras/src/main/java/com/google/gson/mini/StringToValueMapTypeAdapter.java index cc7f66e4..ac55419d 100644 --- a/extras/src/main/java/com/google/gson/mini/MapTypeAdapter.java +++ b/extras/src/main/java/com/google/gson/mini/StringToValueMapTypeAdapter.java @@ -29,9 +29,9 @@ import java.util.LinkedHashMap; import java.util.Map; /** - * Adapt a homogeneous collection of objects. + * Adapt a map whose keys are strings. */ -final class MapTypeAdapter extends TypeAdapter> { +final class StringToValueMapTypeAdapter extends TypeAdapter> { public static final Factory FACTORY = new Factory() { public TypeAdapter create(MiniGson context, TypeToken typeToken) { Type type = typeToken.getType(); @@ -46,27 +46,20 @@ final class MapTypeAdapter extends TypeAdapter> { Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawType); if (keyAndValueTypes[0] != String.class) { - return null; // TODO: return an array-style map adapter + return null; } TypeAdapter valueAdapter = context.getAdapter(TypeToken.get(keyAndValueTypes[1])); - Class constructorType; - - if (rawType == Map.class) { - constructorType = LinkedHashMap.class; - } else { - constructorType = rawType; - } - Constructor constructor; try { + Class constructorType = (rawType == Map.class) ? LinkedHashMap.class : rawType; constructor = constructorType.getConstructor(); } catch (NoSuchMethodException e) { return null; } @SuppressWarnings("unchecked") // we don't define a type parameter for the key or value types - TypeAdapter result = new MapTypeAdapter(valueAdapter, constructor); + TypeAdapter result = new StringToValueMapTypeAdapter(valueAdapter, constructor); return result; } }; @@ -74,7 +67,7 @@ final class MapTypeAdapter extends TypeAdapter> { private final TypeAdapter valueTypeAdapter; private final Constructor> constructor; - public MapTypeAdapter(TypeAdapter valueTypeAdapter, + public StringToValueMapTypeAdapter(TypeAdapter valueTypeAdapter, Constructor> constructor) { this.valueTypeAdapter = valueTypeAdapter; this.constructor = constructor; diff --git a/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java b/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java index 7b1cedec..2c31958c 100644 --- a/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java +++ b/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java @@ -118,6 +118,30 @@ public final class MiniGsonTest extends TestCase { assertEquals(map, mapAdapter.fromJson("{'a':5.0,'b':10.0}")); } + public void testSerialize1dArray() throws IOException { + TypeAdapter arrayAdapter = miniGson.getAdapter(new TypeToken() {}); + assertEquals("[1.0,2.0,3.0]", arrayAdapter.toJson(new double[]{1.0, 2.0, 3.0})); + } + + public void testDeserialize1dArray() throws IOException { + TypeAdapter arrayAdapter = miniGson.getAdapter(new TypeToken() {}); + double[] array = arrayAdapter.fromJson("[1.0,2.0,3.0]"); + assertTrue(Arrays.toString(array), Arrays.equals(new double[]{1.0, 2.0, 3.0}, array)); + } + + public void testSerialize2dArray() throws IOException { + TypeAdapter arrayAdapter = miniGson.getAdapter(new TypeToken() {}); + double[][] array = { {1.0, 2.0 }, { 3.0 } }; + assertEquals("[[1.0,2.0],[3.0]]", arrayAdapter.toJson(array)); + } + + public void testDeserialize2dArray() throws IOException { + TypeAdapter arrayAdapter = miniGson.getAdapter(new TypeToken() {}); + double[][] array = arrayAdapter.fromJson("[[1.0,2.0],[3.0]]"); + double[][] expected = { {1.0, 2.0 }, { 3.0 } }; + assertTrue(Arrays.toString(array), Arrays.deepEquals(expected, array)); + } + static class Truck { double horsePower; List passengers = Collections.emptyList();