You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jclouds.apache.org by ad...@apache.org on 2014/10/30 15:19:23 UTC
git commit: JCLOUDS-750 support serializing auto-value types without
custom type adapters.
Repository: jclouds
Updated Branches:
refs/heads/master 5641efa0c -> e21cbd09c
JCLOUDS-750 support serializing auto-value types without custom type adapters.
Project: http://git-wip-us.apache.org/repos/asf/jclouds/repo
Commit: http://git-wip-us.apache.org/repos/asf/jclouds/commit/e21cbd09
Tree: http://git-wip-us.apache.org/repos/asf/jclouds/tree/e21cbd09
Diff: http://git-wip-us.apache.org/repos/asf/jclouds/diff/e21cbd09
Branch: refs/heads/master
Commit: e21cbd09cb568eef6076033da99448b128310518
Parents: 5641efa
Author: Adrian Cole <ac...@twitter.com>
Authored: Wed Oct 29 21:04:06 2014 -0700
Committer: Adrian Cole <ad...@apache.org>
Committed: Thu Oct 30 07:19:01 2014 -0700
----------------------------------------------------------------------
core/pom.xml | 5 +
...structorAndReflectiveTypeAdapterFactory.java | 22 ++++-
.../test/java/org/jclouds/json/JsonTest.java | 99 +++++++++++++++-----
project/pom.xml | 6 ++
4 files changed, 103 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/jclouds/blob/e21cbd09/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index fb8f86d..eb0c915 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -108,6 +108,11 @@
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
http://git-wip-us.apache.org/repos/asf/jclouds/blob/e21cbd09/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java b/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
index 87e9d32..de985fd 100644
--- a/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
+++ b/core/src/main/java/org/jclouds/json/internal/DeserializationConstructorAndReflectiveTypeAdapterFactory.java
@@ -22,6 +22,7 @@ import static org.jclouds.reflect.Reflection2.typeToken;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
@@ -118,14 +119,25 @@ public final class DeserializationConstructorAndReflectiveTypeAdapterFactory imp
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
com.google.common.reflect.TypeToken<T> token = typeToken(type.getType());
- Invokable<T, T> deserializationCtor = constructorFieldNamingPolicy.getDeserializer(token);
+ Invokable<T, T> deserializationTarget = constructorFieldNamingPolicy.getDeserializer(token);
- if (deserializationCtor == null) {
+ if (deserializationTarget == null) {
return null; // allow GSON to choose the correct Adapter (can't simply return delegateFactory.create())
- } else {
- return new DeserializeIntoParameterizedConstructor<T>(delegateFactory.create(gson, type), deserializationCtor,
- getParameterReaders(gson, deserializationCtor));
}
+ // @AutoValue is SOURCE retention, which means it cannot be looked up at runtime.
+ // Assume abstract types built by static methods are AutoValue.
+ if (Modifier.isAbstract(type.getRawType().getModifiers()) && deserializationTarget.isStatic()) {
+ // Lookup the generated AutoValue class, whose fields must be read for serialization.
+ String packageName = type.getRawType().getPackage().getName();
+ String autoClassName = type.getRawType().getName().replace('$', '_')
+ .replace(packageName + ".", packageName + ".AutoValue_");
+ try {
+ type = (TypeToken<T>) TypeToken.get(Class.forName(autoClassName));
+ } catch (ClassNotFoundException ignored) {
+ }
+ }
+ return new DeserializeIntoParameterizedConstructor<T>(delegateFactory.create(gson, type), deserializationTarget,
+ getParameterReaders(gson, deserializationTarget));
}
private final class DeserializeIntoParameterizedConstructor<T> extends TypeAdapter<T> {
http://git-wip-us.apache.org/repos/asf/jclouds/blob/e21cbd09/core/src/test/java/org/jclouds/json/JsonTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/jclouds/json/JsonTest.java b/core/src/test/java/org/jclouds/json/JsonTest.java
index 6a0b6aa..cf477b4 100644
--- a/core/src/test/java/org/jclouds/json/JsonTest.java
+++ b/core/src/test/java/org/jclouds/json/JsonTest.java
@@ -20,24 +20,35 @@ import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.primitives.Bytes.asList;
import static org.testng.Assert.assertEquals;
+import java.io.IOException;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DefaultExclusionStrategy;
import org.testng.annotations.Test;
-import com.google.common.base.Objects;
+import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.gson.FieldAttributes;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.FieldNamingStrategy;
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
+import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
@Test
@@ -214,7 +225,8 @@ public class JsonTest {
EnumInsideWithParser.Test.UNRECOGNIZED);
}
- private abstract static class UpperCamelCasedType {
+ @AutoValue
+ abstract static class UpperCamelCasedType {
abstract String id();
@Nullable abstract Map<String, String> volumes();
@@ -222,7 +234,7 @@ public class JsonTest {
// Currently, this only works for deserialization. Need to set a naming policy for serialization!
@SerializedNames({ "Id", "Volumes" })
private static UpperCamelCasedType create(String id, Map<String, String> volumes) {
- return new UpperCamelCasedTypeImpl(id, volumes);
+ return new AutoValue_JsonTest_UpperCamelCasedType(id, volumes);
}
}
@@ -251,36 +263,75 @@ public class JsonTest {
UpperCamelCasedType.create("1234", null));
}
- private static class UpperCamelCasedTypeImpl extends UpperCamelCasedType {
- private final String id;
- private final Map<String, String> volumes;
+ @AutoValue
+ abstract static class NestedCamelCasedType {
+ abstract UpperCamelCasedType item();
- private UpperCamelCasedTypeImpl(String id, Map<String, String> volumes) {
- this.id = id;
- this.volumes = volumes;
- }
+ abstract List<UpperCamelCasedType> items();
- @Override String id() {
- return id;
+ // Currently, this only works for deserialization. Need to set a naming policy for serialization!
+ @SerializedNames({ "Item", "Items" })
+ private static NestedCamelCasedType create(UpperCamelCasedType item, List<UpperCamelCasedType> items) {
+ return new AutoValue_JsonTest_NestedCamelCasedType(item, items);
}
+ }
- @Override @Nullable Map<String, String> volumes() {
- return volumes;
- }
+ private final NestedCamelCasedType nested = NestedCamelCasedType
+ .create(UpperCamelCasedType.create("1234", Collections.<String, String>emptyMap()),
+ Arrays.asList(UpperCamelCasedType.create("5678", ImmutableMap.of("Foo", "Bar"))));
- @Override public boolean equals(Object o) {
- if (o == this) {
- return true;
+ public void nestedCamelCasedType() {
+ Json json = Guice.createInjector(new GsonModule(), new AbstractModule() {
+ @Override protected void configure() {
+ bind(FieldNamingStrategy.class).toInstance(FieldNamingPolicy.UPPER_CAMEL_CASE);
}
- if (o instanceof UpperCamelCasedType) {
- UpperCamelCasedType that = (UpperCamelCasedType) o;
- return Objects.equal(this.id, that.id()) && Objects.equal(this.volumes, that.volumes());
+ }).getInstance(Json.class);
+
+ String spinalJson = "{\"Item\":{\"Id\":\"1234\",\"Volumes\":{}},\"Items\":[{\"Id\":\"5678\",\"Volumes\":{\"Foo\":\"Bar\"}}]}";
+
+ assertEquals(json.toJson(nested), spinalJson);
+ assertEquals(json.fromJson(spinalJson, NestedCamelCasedType.class), nested);
+ }
+
+ public void nestedCamelCasedTypeOverriddenTypeAdapterFactory() {
+ Json json = Guice.createInjector(new GsonModule(), new AbstractModule() {
+ @Override protected void configure() {
+ }
+
+ @Provides public Set<TypeAdapterFactory> typeAdapterFactories() {
+ return ImmutableSet.<TypeAdapterFactory>of(new NestedCamelCasedTypeAdapterFactory());
+ }
+ }).getInstance(Json.class);
+
+ assertEquals(json.toJson(nested), "{\"id\":\"1234\",\"count\":1}");
+ assertEquals(json.fromJson("{\"id\":\"1234\",\"count\":1}", NestedCamelCasedType.class), nested);
+ }
+
+ private class NestedCamelCasedTypeAdapterFactory extends TypeAdapter<NestedCamelCasedType>
+ implements TypeAdapterFactory {
+
+ @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
+ if (!(NestedCamelCasedType.class.isAssignableFrom(typeToken.getRawType()))) {
+ return null;
}
- return false;
+ return (TypeAdapter<T>) this;
+ }
+
+ @Override public void write(JsonWriter out, NestedCamelCasedType value) throws IOException {
+ out.beginObject();
+ out.name("id").value(value.item().id());
+ out.name("count").value(value.items().size());
+ out.endObject();
}
- @Override public int hashCode() {
- return Objects.hashCode(id, volumes);
+ @Override public NestedCamelCasedType read(JsonReader in) throws IOException {
+ in.beginObject();
+ in.nextName();
+ in.nextString();
+ in.nextName();
+ in.nextInt();
+ in.endObject();
+ return nested;
}
}
}
http://git-wip-us.apache.org/repos/asf/jclouds/blob/e21cbd09/project/pom.xml
----------------------------------------------------------------------
diff --git a/project/pom.xml b/project/pom.xml
index 833a447..d324ae4 100644
--- a/project/pom.xml
+++ b/project/pom.xml
@@ -210,6 +210,7 @@
<surefire.version>2.17</surefire.version>
<assertj-core.version>1.6.1</assertj-core.version>
<assertj-guava.version>1.2.0</assertj-guava.version>
+ <auto-value.version>1.0-rc2</auto-value.version>
<http.proxyHost />
<http.proxyPort />
<jclouds.wire.httpstream.url>http://archive.apache.org/dist/commons/logging/binaries/commons-logging-1.1.1-bin.tar.gz</jclouds.wire.httpstream.url>
@@ -304,6 +305,11 @@
<artifactId>assertj-guava</artifactId>
<version>${assertj-guava.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.google.auto.value</groupId>
+ <artifactId>auto-value</artifactId>
+ <version>${auto-value.version}</version>
+ </dependency>
</dependencies>
</dependencyManagement>
<dependencies>