Issue 559:update to gson 1.7.1

This commit is contained in:
Adrian Cole 2011-05-14 18:01:17 -07:00
parent e29bad7f42
commit 3bb41050d0
12 changed files with 170 additions and 159 deletions

View File

@ -105,7 +105,7 @@
<dependency> <dependency>
<groupId>com.google.code.gson</groupId> <groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId> <artifactId>gson</artifactId>
<version>1.6</version> <version>1.7.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>

View File

@ -1,32 +0,0 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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;
/**
* handles the limitation in gson 1.6 where
* {@link GsonBuilder#registerTypeHierarchyAdapter(Class, Object)} is package private.
*
* @see <a href="http://code.google.com/p/google-gson/issues/detail?id=271" >gson issue 271</a>
* @author Adrian Cole
*/
public class JcloudsGsonPackageAccessor {
public static GsonBuilder registerTypeHierarchyAdapter(GsonBuilder builder, Class<?> baseType, Object typeAdapter) {
return builder.registerTypeHierarchyAdapter(baseType, typeAdapter);
}
}

View File

@ -23,11 +23,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException; import java.io.IOException;
/** /**
* The gson project use package to control access to their objects. However, * The gson project use package to control access to their objects. However, this prevents us from
* this prevents us from doing valid work, like controling the json emitted on a * doing valid work, like controling the json emitted on a per-object basis. This is here to afford
* per-object basis. This is here to afford us to do this. * us to do this.
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href="http://code.google.com/p/google-gson/issues/detail?id=326"/>
*/ */
public final class JsonLiteral extends JsonElement { public final class JsonLiteral extends JsonElement {
private final CharSequence literal; private final CharSequence literal;

View File

@ -1,89 +0,0 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* 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;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.jclouds.json.internal.ParseObjectFromElement;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>, InstanceCreator<Map> {
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject map = new JsonObject();
Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) {
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
}
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
Object value = entry.getValue();
JsonElement valueElement;
if (value == null) {
valueElement = JsonNull.createJsonNull();
} else {
Type childType = (childGenericType == null) ? value.getClass() : childGenericType;
valueElement = context.serialize(value, childType);
}
map.add(String.valueOf(entry.getKey()), valueElement);
}
return map;
}
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Map.
Map<Object, Object> map = constructMapType(typeOfT, context);
TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT);
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType());
// START JCLOUDS PATCH
Object value = null;
if (mapTypeInfo.getValueType() == Object.class) {
value = ParseObjectFromElement.SINGLETON.apply(entry.getValue());
}
if (value == null) {
value = context.deserialize(entry.getValue(), mapTypeInfo.getValueType());
}
// END JCLOUDS PATCH
map.put(key, value);
}
return map;
}
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Map) objectConstructor.construct(mapType);
}
public Map createInstance(Type type) {
return new LinkedHashMap();
}
@Override
public String toString() {
return MapTypeAdapter.class.getSimpleName();
}
}

View File

@ -0,0 +1,90 @@
/*
* 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;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Set;
import org.jclouds.json.internal.ParseObjectFromElement;
import com.google.gson.internal.$Gson$Types;
/**
* Default serialization and deserialization of a map type. This implementation really only works
* well with simple primitive types as the map key. If the key is not a simple primitive then the
* object is {@code toString}ed and that value is used as its key.
* <p/>
* Patched depending on <a href="http://code.google.com/p/google-gson/issues/detail?id=325">this</a>
* @author Joel Leitch
*/
@SuppressWarnings("unchecked")
public final class ObjectMapTypeAdapter extends BaseMapTypeAdapter {
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject map = new JsonObject();
Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) {
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(typeOfSrc);
childGenericType = $Gson$Types.getMapKeyAndValueTypes(typeOfSrc, rawTypeOfSrc)[1];
}
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
Object value = entry.getValue();
JsonElement valueElement;
if (value == null) {
valueElement = JsonNull.createJsonNull();
} else {
Type childType = (childGenericType == null)
? value.getClass() : childGenericType;
valueElement = serialize(context, value, childType);
}
map.add(String.valueOf(entry.getKey()), valueElement);
}
return map;
}
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Map.
Map<Object, Object> map = constructMapType(typeOfT, context);
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(typeOfT, $Gson$Types.getRawType(typeOfT));
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueTypes[0]);
// START JCLOUDS PATCH
// http://code.google.com/p/google-gson/issues/detail?id=325
Object value = null;
if (keyAndValueTypes[1] == Object.class) {
value = ParseObjectFromElement.SINGLETON.apply(entry.getValue());
}
if (value == null) {
value = context.deserialize(entry.getValue(), keyAndValueTypes[1]);
}
// END JCLOUDS PATCH
map.put(key, value);
}
return map;
}
@Override
public String toString() {
return MapTypeAdapter.class.getSimpleName();
}
}

View File

@ -1,8 +1,6 @@
/** /*
* Copyright (C) 2010 Google Inc.
* *
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
@ -14,8 +12,8 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* ====================================================================
*/ */
package com.google.gson; package com.google.gson;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
@ -104,7 +102,8 @@ final class Streams {
if (serializeNulls) { if (serializeNulls) {
writer.nullValue(); writer.nullValue();
} }
//BEGIN JCLOUDS PATCH //BEGIN JCLOUDS PATCH
// * @see <a href="http://code.google.com/p/google-gson/issues/detail?id=326"/>
} else if (element instanceof JsonLiteral ) { } else if (element instanceof JsonLiteral ) {
writer.value(JsonLiteral.class.cast(element)); writer.value(JsonLiteral.class.cast(element));
//END JCLOUDS PATCH //END JCLOUDS PATCH

View File

@ -1,21 +1,19 @@
/** /*
* Copyright (C) 2010 Google Inc.
* *
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* ====================================================================
*/ */
package com.google.gson.stream; package com.google.gson.stream;
import java.io.Closeable; import java.io.Closeable;
@ -344,7 +342,7 @@ public final class JsonWriter implements Closeable {
return this; return this;
} }
//BEGIN JCLOUDS PATCH //BEGIN JCLOUDS PATCH
// * @see <a href="http://code.google.com/p/google-gson/issues/detail?id=326"/>
/** /**
* Writes {@code value} literally * Writes {@code value} literally
* *
@ -356,7 +354,6 @@ public final class JsonWriter implements Closeable {
return this; return this;
} }
//END JCLOUDS PATCH //END JCLOUDS PATCH
/** /**
* Encodes {@code value}. * Encodes {@code value}.
* *

View File

@ -27,6 +27,7 @@ import org.jclouds.util.Patterns;
* As String is final, using a different marker to imply this is a json object * As String is final, using a different marker to imply this is a json object
* *
* @author Adrian Cole * @author Adrian Cole
* @see <a href="http://code.google.com/p/google-gson/issues/detail?id=326"/>
*/ */
public class JsonBall implements java.io.Serializable, Comparable<String>, CharSequence { public class JsonBall implements java.io.Serializable, Comparable<String>, CharSequence {

View File

@ -36,12 +36,11 @@ import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
import org.jclouds.json.internal.GsonWrapper; import org.jclouds.json.internal.GsonWrapper;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.primitives.Bytes; import com.google.common.primitives.Bytes;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JcloudsGsonPackageAccessor;
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@ -50,7 +49,7 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer; import com.google.gson.JsonSerializer;
import com.google.gson.MapTypeAdapter; import com.google.gson.ObjectMapTypeAdapter;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.ImplementedBy; import com.google.inject.ImplementedBy;
@ -68,12 +67,11 @@ public class GsonModule extends AbstractModule {
@Provides @Provides
@Singleton @Singleton
Gson provideGson(JsonBallAdapter jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter, Gson provideGson(JsonBallAdapter jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
ByteArrayAdapter byteArrayAdapter, SerializePropertiesDefaults propertiesAdapter, JsonAdapterBindings bindings) ByteArrayAdapter byteArrayAdapter, SerializePropertiesDefaults propertiesAdapter,
throws ClassNotFoundException, Exception { JsonAdapterBindings bindings) throws ClassNotFoundException, Exception {
GsonBuilder builder = new GsonBuilder(); GsonBuilder builder = new GsonBuilder();
JcloudsGsonPackageAccessor.registerTypeHierarchyAdapter(builder, Enum.class, builder.registerTypeHierarchyAdapter(Enum.class, new EnumTypeAdapterThatReturnsFromValue());
new EnumTypeAdapterThatReturnsFromValue()); builder.registerTypeHierarchyAdapter(Map.class, new ObjectMapTypeAdapter());
JcloudsGsonPackageAccessor.registerTypeHierarchyAdapter(builder, Map.class, new MapTypeAdapter());
builder.registerTypeAdapter(JsonBall.class, jsonAdapter); builder.registerTypeAdapter(JsonBall.class, jsonAdapter);
builder.registerTypeAdapter(Date.class, adapter); builder.registerTypeAdapter(Date.class, adapter);
builder.registerTypeAdapter(Properties.class, propertiesAdapter); builder.registerTypeAdapter(Properties.class, propertiesAdapter);
@ -86,6 +84,7 @@ public class GsonModule extends AbstractModule {
return builder.create(); return builder.create();
} }
// http://code.google.com/p/google-gson/issues/detail?id=326
@ImplementedBy(JsonBallAdapterImpl.class) @ImplementedBy(JsonBallAdapterImpl.class)
public static interface JsonBallAdapter extends JsonSerializer<JsonBall>, JsonDeserializer<JsonBall> { public static interface JsonBallAdapter extends JsonSerializer<JsonBall>, JsonDeserializer<JsonBall> {
@ -99,7 +98,7 @@ public class GsonModule extends AbstractModule {
} }
public JsonBall deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public JsonBall deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return new JsonBall(json.toString()); return new JsonBall(json.toString());
} }
@ -125,7 +124,7 @@ public class GsonModule extends AbstractModule {
@Override @Override
public List<Byte> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public List<Byte> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return Bytes.asList(CryptoStreams.hex(json.getAsString())); return Bytes.asList(CryptoStreams.hex(json.getAsString()));
} }
@ -141,7 +140,7 @@ public class GsonModule extends AbstractModule {
@Override @Override
public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public byte[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return CryptoStreams.hex(json.getAsString()); return CryptoStreams.hex(json.getAsString());
} }
@ -165,7 +164,7 @@ public class GsonModule extends AbstractModule {
} }
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
String toParse = json.getAsJsonPrimitive().getAsString(); String toParse = json.getAsJsonPrimitive().getAsString();
try { try {
return dateService.iso8601DateParse(toParse); return dateService.iso8601DateParse(toParse);
@ -212,7 +211,7 @@ public class GsonModule extends AbstractModule {
} }
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
String toParse = json.getAsJsonPrimitive().getAsString(); String toParse = json.getAsJsonPrimitive().getAsString();
Date toReturn = dateService.cDateParse(toParse); Date toReturn = dateService.cDateParse(toParse);
return toReturn; return toReturn;
@ -228,7 +227,7 @@ public class GsonModule extends AbstractModule {
} }
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
long toParse = json.getAsJsonPrimitive().getAsLong(); long toParse = json.getAsJsonPrimitive().getAsLong();
if (toParse == -1) if (toParse == -1)
return null; return null;

View File

@ -27,7 +27,7 @@ import com.google.gson.JsonObject;
/** /**
* Exposes the JsonObject as a map so that we can use gauva apis on it. * Exposes the JsonObject as a map so that we can use gauva apis on it.
* * http://code.google.com/p/google-gson/issues/detail?id=325
* @author Adrian Cole * @author Adrian Cole
*/ */
public enum JsonObjectAsMap implements Function<JsonObject, Map<String, JsonElement>> { public enum JsonObjectAsMap implements Function<JsonObject, Map<String, JsonElement>> {

View File

@ -24,12 +24,11 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.google.gson.MapTypeAdapter;
/** /**
* This is a class that helps the default {@link MapTypeAdapter} make a sane object graph when the * This is a class that helps the default {@link MapTypeAdapter} make a sane object graph when the
* value is set to {@code Object} * value is set to {@code Object}
* * http://code.google.com/p/google-gson/issues/detail?id=325
* @author Adrian Cole * @author Adrian Cole
*/ */
public enum ParseObjectFromElement implements Function<JsonElement, Object> { public enum ParseObjectFromElement implements Function<JsonElement, Object> {

View File

@ -37,6 +37,52 @@ import com.google.inject.TypeLiteral;
public class JsonTest { public class JsonTest {
private Json json = Guice.createInjector(new GsonModule()).getInstance(Json.class); private Json json = Guice.createInjector(new GsonModule()).getInstance(Json.class);
private static class ObjectNoDefaultConstructor {
private final String stringValue;
private final int intValue;
public ObjectNoDefaultConstructor(String stringValue, int intValue) {
this.stringValue = stringValue;
this.intValue = intValue;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + intValue;
result = prime * result + ((stringValue == null) ? 0 : stringValue.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ObjectNoDefaultConstructor other = (ObjectNoDefaultConstructor) obj;
if (intValue != other.intValue)
return false;
if (stringValue == null) {
if (other.stringValue != null)
return false;
} else if (!stringValue.equals(other.stringValue))
return false;
return true;
}
}
public void testObjectNoDefaultConstructor() {
ObjectNoDefaultConstructor obj = new ObjectNoDefaultConstructor("foo", 1);
assertEquals(json.toJson(obj), "{\"stringValue\":\"foo\",\"intValue\":1}");
ObjectNoDefaultConstructor obj2 = json.fromJson(json.toJson(obj), ObjectNoDefaultConstructor.class);
assertEquals(obj2, obj);
assertEquals(json.toJson(obj2), json.toJson(obj));
}
private static class EnumInside { private static class EnumInside {
private static enum Test { private static enum Test {
FOO, BAR; FOO, BAR;
@ -66,7 +112,7 @@ public class JsonTest {
map.put("map", ImmutableMap.of("key", "value")); map.put("map", ImmutableMap.of("key", "value"));
map.put("list", ImmutableList.of("key", "value")); map.put("list", ImmutableList.of("key", "value"));
assertEquals(json.toJson(map), assertEquals(json.toJson(map),
"{\"string\":\"string\",\"map\":{\"key\":\"value\"},\"list\":[\"key\",\"value\"],\"boolean\":true,\"number\":1}"); "{\"string\":\"string\",\"map\":{\"key\":\"value\"},\"list\":[\"key\",\"value\"],\"boolean\":true,\"number\":1}");
Map<String, Object> map2 = json.fromJson(json.toJson(map), new TypeLiteral<Map<String, Object>>() { Map<String, Object> map2 = json.fromJson(json.toJson(map), new TypeLiteral<Map<String, Object>>() {
}.getType()); }.getType());
assertEquals(map2, map); assertEquals(map2, map);
@ -121,12 +167,12 @@ public class JsonTest {
public void testDeserializeEnumWithParser() { public void testDeserializeEnumWithParser() {
assertEquals(json.fromJson("{enumValue : \"FOO\"}", EnumInsideWithParser.class).enumValue, assertEquals(json.fromJson("{enumValue : \"FOO\"}", EnumInsideWithParser.class).enumValue,
EnumInsideWithParser.Test.FOO); EnumInsideWithParser.Test.FOO);
} }
public void testDeserializeEnumWithParserAndBadValue() { public void testDeserializeEnumWithParserAndBadValue() {
assertEquals(json.fromJson("{enumValue : \"sd\"}", EnumInsideWithParser.class).enumValue, assertEquals(json.fromJson("{enumValue : \"sd\"}", EnumInsideWithParser.class).enumValue,
EnumInsideWithParser.Test.UNRECOGNIZED); EnumInsideWithParser.Test.UNRECOGNIZED);
} }
} }