make it possible to deserialize into ctors that have immutable collection parameters

This commit is contained in:
adriancole 2013-03-13 11:56:58 -07:00
parent 7596205774
commit ef2718629f
5 changed files with 325 additions and 269 deletions

View File

@ -26,6 +26,7 @@ import javax.inject.Inject;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter; import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapter;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapterFactory;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
@ -84,10 +85,10 @@ public class CloudStackParserModule extends AbstractModule {
public static final class Adapter<E> extends TypeAdapter<Iterable<E>> { public static final class Adapter<E> extends TypeAdapter<Iterable<E>> {
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate; private final IterableTypeAdapter<E> delegate;
public Adapter(TypeAdapter<E> elementAdapter) { public Adapter(TypeAdapter<E> elementAdapter) {
this.delegate = new IterableTypeAdapterFactory.IterableTypeAdapter<E>(elementAdapter); this.delegate = new IterableTypeAdapter<E>(elementAdapter);
nullSafe(); nullSafe();
} }

View File

@ -25,6 +25,7 @@ import java.util.Set;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter; import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapter;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapterFactory;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -63,10 +64,10 @@ public class KeystoneParserModule extends AbstractModule {
public static final class Adapter<E> extends TypeAdapter<Set<E>> { public static final class Adapter<E> extends TypeAdapter<Set<E>> {
private final SetTypeAdapterFactory.SetTypeAdapter<E> delegate; private final SetTypeAdapter<E> delegate;
public Adapter(TypeAdapter<E> elementAdapter) { public Adapter(TypeAdapter<E> elementAdapter) {
this.delegate = new SetTypeAdapterFactory.SetTypeAdapter<E>(elementAdapter); this.delegate = new SetTypeAdapter<E>(elementAdapter);
nullSafe(); nullSafe();
} }

View File

@ -46,7 +46,10 @@ import org.jclouds.json.internal.NamingStrategies.ExtractNamed;
import org.jclouds.json.internal.NamingStrategies.ExtractSerializedName; import org.jclouds.json.internal.NamingStrategies.ExtractSerializedName;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.CollectionTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.CollectionTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.FluentIterableTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.FluentIterableTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ImmutableListTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ImmutableSetTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ListTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MultimapTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MultimapTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapterFactory;
@ -88,9 +91,10 @@ public class GsonModule extends AbstractModule {
@Singleton @Singleton
Gson provideGson(TypeAdapter<JsonBall> jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter, Gson provideGson(TypeAdapter<JsonBall> jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings, ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings,
OptionalTypeAdapterFactory optional, SetTypeAdapterFactory set, MapTypeAdapterFactory map, OptionalTypeAdapterFactory optional, SetTypeAdapterFactory set, ImmutableSetTypeAdapterFactory immutableSet,
MultimapTypeAdapterFactory multimap, IterableTypeAdapterFactory iterable, MapTypeAdapterFactory map, MultimapTypeAdapterFactory multimap, IterableTypeAdapterFactory iterable,
CollectionTypeAdapterFactory collection, FluentIterableTypeAdapterFactory fluentIterable, CollectionTypeAdapterFactory collection, ListTypeAdapterFactory list,
ImmutableListTypeAdapterFactory immutableList, FluentIterableTypeAdapterFactory fluentIterable,
DefaultExclusionStrategy exclusionStrategy) { DefaultExclusionStrategy exclusionStrategy) {
FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of( FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(ImmutableSet.of(
@ -109,7 +113,10 @@ public class GsonModule extends AbstractModule {
builder.registerTypeAdapterFactory(optional); builder.registerTypeAdapterFactory(optional);
builder.registerTypeAdapterFactory(iterable); builder.registerTypeAdapterFactory(iterable);
builder.registerTypeAdapterFactory(collection); builder.registerTypeAdapterFactory(collection);
builder.registerTypeAdapterFactory(list);
builder.registerTypeAdapterFactory(immutableList);
builder.registerTypeAdapterFactory(set); builder.registerTypeAdapterFactory(set);
builder.registerTypeAdapterFactory(immutableSet);
builder.registerTypeAdapterFactory(map); builder.registerTypeAdapterFactory(map);
builder.registerTypeAdapterFactory(multimap); builder.registerTypeAdapterFactory(multimap);
builder.registerTypeAdapterFactory(fluentIterable); builder.registerTypeAdapterFactory(fluentIterable);

View File

@ -25,6 +25,7 @@ import java.io.IOException;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
@ -61,15 +62,73 @@ public class NullFilteringTypeAdapterFactories {
param)); param));
} }
public static class IterableTypeAdapterFactory implements TypeAdapterFactory { public static final class IterableTypeAdapter<E> extends TypeAdapter<Iterable<E>> {
private final TypeAdapter<E> elementAdapter;
public IterableTypeAdapter(TypeAdapter<E> elementAdapter) {
this.elementAdapter = elementAdapter;
nullSafe();
}
public void write(JsonWriter out, Iterable<E> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginArray();
for (E element : value)
elementAdapter.write(out, element);
out.endArray();
}
public Iterable<E> read(JsonReader in) throws IOException {
return readAndBuild(in, ImmutableList.<E> builder());
}
@SuppressWarnings("unchecked")
protected <C extends Iterable<E>, B extends ImmutableCollection.Builder<E>> C readAndBuild(JsonReader in,
B builder) throws IOException {
in.beginArray();
while (in.hasNext()) {
E element = elementAdapter.read(in);
if (element != null)
builder.add(element);
}
in.endArray();
return (C) builder.build();
}
@Override
public int hashCode() {
return elementAdapter.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
IterableTypeAdapter<?> that = IterableTypeAdapter.class.cast(obj);
return equal(this.elementAdapter, that.elementAdapter);
}
@Override
public String toString() {
return toStringHelper(this).add("elementAdapter", elementAdapter).toString();
}
}
public static class ImmutableListTypeAdapterFactory implements TypeAdapterFactory {
protected final Class<?> declaring; protected final Class<?> declaring;
public IterableTypeAdapterFactory() { public ImmutableListTypeAdapterFactory() {
this(Iterable.class); this(ImmutableList.class);
} }
protected IterableTypeAdapterFactory(Class<?> declaring) { protected ImmutableListTypeAdapterFactory(Class<?> declaring) {
this.declaring = declaring; this.declaring = declaring;
} }
@ -88,164 +147,124 @@ public class NullFilteringTypeAdapterFactories {
return (TypeAdapter<I>) new IterableTypeAdapter<E>(elementAdapter); return (TypeAdapter<I>) new IterableTypeAdapter<E>(elementAdapter);
} }
public static final class IterableTypeAdapter<E> extends TypeAdapter<Iterable<E>> {
private final TypeAdapter<E> elementAdapter;
public IterableTypeAdapter(TypeAdapter<E> elementAdapter) {
this.elementAdapter = elementAdapter;
nullSafe();
}
public void write(JsonWriter out, Iterable<E> value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.beginArray();
for (E element : value)
elementAdapter.write(out, element);
out.endArray();
}
public Iterable<E> read(JsonReader in) throws IOException {
return readAndBuild(in, ImmutableList.<E> builder());
}
@SuppressWarnings("unchecked")
protected <C extends Iterable<E>, B extends ImmutableCollection.Builder<E>> C readAndBuild(JsonReader in,
B builder) throws IOException {
in.beginArray();
while (in.hasNext()) {
E element = elementAdapter.read(in);
if (element != null)
builder.add(element);
}
in.endArray();
return (C) builder.build();
}
@Override
public int hashCode() {
return elementAdapter.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
IterableTypeAdapter<?> that = IterableTypeAdapter.class.cast(obj);
return equal(this.elementAdapter, that.elementAdapter);
}
@Override
public String toString() {
return toStringHelper(this).add("elementAdapter", elementAdapter).toString();
}
}
} }
public static class CollectionTypeAdapterFactory extends IterableTypeAdapterFactory { public static class IterableTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
public IterableTypeAdapterFactory() {
super(Iterable.class);
}
}
public static class CollectionTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
public CollectionTypeAdapterFactory() { public CollectionTypeAdapterFactory() {
super(Collection.class); super(Collection.class);
} }
}
@SuppressWarnings("unchecked") public static class ListTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) { public ListTypeAdapterFactory() {
return (TypeAdapter<I>) new CollectionTypeAdapter<E>(elementAdapter); super(List.class);
}
public static final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate;
public CollectionTypeAdapter(TypeAdapter<E> elementAdapter) {
this.delegate = new IterableTypeAdapterFactory.IterableTypeAdapter<E>(elementAdapter);
nullSafe();
}
public void write(JsonWriter out, Collection<E> value) throws IOException {
this.delegate.write(out, value);
}
public Collection<E> read(JsonReader in) throws IOException {
return delegate.readAndBuild(in, ImmutableList.<E> builder());
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
CollectionTypeAdapter<?> that = CollectionTypeAdapter.class.cast(obj);
return equal(this.delegate, that.delegate);
}
@Override
public String toString() {
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
}
} }
} }
public static class SetTypeAdapterFactory extends IterableTypeAdapterFactory { public static final class SetTypeAdapter<E> extends TypeAdapter<Set<E>> {
public SetTypeAdapterFactory() {
super(Set.class); private final IterableTypeAdapter<E> delegate;
public SetTypeAdapter(TypeAdapter<E> elementAdapter) {
this.delegate = new IterableTypeAdapter<E>(elementAdapter);
nullSafe();
}
public void write(JsonWriter out, Set<E> value) throws IOException {
this.delegate.write(out, value);
}
public Set<E> read(JsonReader in) throws IOException {
return delegate.readAndBuild(in, ImmutableSet.<E> builder());
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
SetTypeAdapter<?> that = SetTypeAdapter.class.cast(obj);
return equal(this.delegate, that.delegate);
}
@Override
public String toString() {
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
}
}
public static class ImmutableSetTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
public ImmutableSetTypeAdapterFactory() {
this(ImmutableSet.class);
}
protected ImmutableSetTypeAdapterFactory(Class<?> declaring) {
super(declaring);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) { protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
return (TypeAdapter<I>) new SetTypeAdapter<E>(elementAdapter); return (TypeAdapter<I>) new SetTypeAdapter<E>(elementAdapter);
} }
}
public static final class SetTypeAdapter<E> extends TypeAdapter<Set<E>> { public static class SetTypeAdapterFactory extends ImmutableSetTypeAdapterFactory {
public SetTypeAdapterFactory() {
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate; super(Set.class);
public SetTypeAdapter(TypeAdapter<E> elementAdapter) {
this.delegate = new IterableTypeAdapterFactory.IterableTypeAdapter<E>(elementAdapter);
nullSafe();
}
public void write(JsonWriter out, Set<E> value) throws IOException {
this.delegate.write(out, value);
}
public Set<E> read(JsonReader in) throws IOException {
return delegate.readAndBuild(in, ImmutableSet.<E> builder());
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
SetTypeAdapter<?> that = SetTypeAdapter.class.cast(obj);
return equal(this.delegate, that.delegate);
}
@Override
public String toString() {
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
}
} }
} }
public static class FluentIterableTypeAdapterFactory extends IterableTypeAdapterFactory { private static final class FluentIterableTypeAdapter<E> extends TypeAdapter<FluentIterable<E>> {
private final IterableTypeAdapter<E> delegate;
public FluentIterableTypeAdapter(TypeAdapter<E> elementAdapter) {
this.delegate = new IterableTypeAdapter<E>(elementAdapter);
nullSafe();
}
public void write(JsonWriter out, FluentIterable<E> value) throws IOException {
this.delegate.write(out, value.toList());
}
public FluentIterable<E> read(JsonReader in) throws IOException {
return FluentIterable.from(delegate.read(in));
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
FluentIterableTypeAdapter<?> that = FluentIterableTypeAdapter.class.cast(obj);
return equal(this.delegate, that.delegate);
}
@Override
public String toString() {
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
}
}
public static class FluentIterableTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
public FluentIterableTypeAdapterFactory() { public FluentIterableTypeAdapterFactory() {
super(FluentIterable.class); super(FluentIterable.class);
} }
@ -254,43 +273,64 @@ public class NullFilteringTypeAdapterFactories {
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) { protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
return (TypeAdapter<I>) new FluentIterableTypeAdapter<E>(elementAdapter); return (TypeAdapter<I>) new FluentIterableTypeAdapter<E>(elementAdapter);
} }
}
public static final class FluentIterableTypeAdapter<E> extends TypeAdapter<FluentIterable<E>> { private static final class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate; protected final TypeAdapter<K> keyAdapter;
protected final TypeAdapter<V> valueAdapter;
public FluentIterableTypeAdapter(TypeAdapter<E> elementAdapter) { protected MapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
this.delegate = new IterableTypeAdapterFactory.IterableTypeAdapter<E>(elementAdapter); this.keyAdapter = keyAdapter;
nullSafe(); this.valueAdapter = valueAdapter;
nullSafe();
}
public void write(JsonWriter out, Map<K, V> value) throws IOException {
if (value == null) {
out.nullValue();
return;
} }
out.beginObject();
public void write(JsonWriter out, FluentIterable<E> value) throws IOException { for (Map.Entry<K, V> element : value.entrySet()) {
this.delegate.write(out, value.toList()); out.name(String.valueOf(element.getKey()));
valueAdapter.write(out, element.getValue());
} }
out.endObject();
}
public FluentIterable<E> read(JsonReader in) throws IOException { public Map<K, V> read(JsonReader in) throws IOException {
return FluentIterable.from(delegate.read(in)); ImmutableMap.Builder<K, V> result = ImmutableMap.builder();
in.beginObject();
while (in.hasNext()) {
JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
K name = keyAdapter.read(in);
V value = valueAdapter.read(in);
if (value != null)
result.put(name, value);
} }
in.endObject();
return result.build();
}
@Override @Override
public int hashCode() { public int hashCode() {
return delegate.hashCode(); return Objects.hashCode(keyAdapter, valueAdapter);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null || getClass() != obj.getClass()) if (obj == null || getClass() != obj.getClass())
return false; return false;
FluentIterableTypeAdapter<?> that = FluentIterableTypeAdapter.class.cast(obj); MapTypeAdapter<?, ?> that = MapTypeAdapter.class.cast(obj);
return equal(this.delegate, that.delegate); return equal(this.keyAdapter, that.keyAdapter) && equal(this.valueAdapter, that.valueAdapter);
} }
@Override @Override
public String toString() { public String toString() {
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString(); return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString();
}
} }
} }
@ -321,64 +361,49 @@ public class NullFilteringTypeAdapterFactories {
protected <K, V, T> TypeAdapter<T> newAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) { protected <K, V, T> TypeAdapter<T> newAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
return (TypeAdapter<T>) new MapTypeAdapter<K, V>(keyAdapter, valueAdapter); return (TypeAdapter<T>) new MapTypeAdapter<K, V>(keyAdapter, valueAdapter);
} }
}
public static final class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> { private static final class MultimapTypeAdapter<K, V> extends TypeAdapter<Multimap<K, V>> {
protected final TypeAdapter<K> keyAdapter; private final MapTypeAdapter<K, Iterable<V>> delegate;
protected final TypeAdapter<V> valueAdapter;
protected MapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) { public MultimapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
this.keyAdapter = keyAdapter; this.delegate = new MapTypeAdapter<K, Iterable<V>>(keyAdapter,
this.valueAdapter = valueAdapter; new IterableTypeAdapter<V>(valueAdapter));
nullSafe(); nullSafe();
} }
public void write(JsonWriter out, Map<K, V> value) throws IOException { @SuppressWarnings("unchecked")
if (value == null) { public void write(JsonWriter out, Multimap<K, V> value) throws IOException {
out.nullValue(); this.delegate.write(out, Map.class.cast(value.asMap()));
return; }
}
out.beginObject();
for (Map.Entry<K, V> element : value.entrySet()) {
out.name(String.valueOf(element.getKey()));
valueAdapter.write(out, element.getValue());
}
out.endObject();
}
public Map<K, V> read(JsonReader in) throws IOException { public Multimap<K, V> read(JsonReader in) throws IOException {
ImmutableMap.Builder<K, V> result = ImmutableMap.builder(); ImmutableMultimap.Builder<K, V> builder = ImmutableMultimap.<K, V> builder();
in.beginObject(); for (Entry<K, Iterable<V>> entry : delegate.read(in).entrySet())
while (in.hasNext()) { builder.putAll(entry.getKey(), entry.getValue());
JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in); return builder.build();
K name = keyAdapter.read(in); }
V value = valueAdapter.read(in);
if (value != null)
result.put(name, value);
}
in.endObject();
return result.build();
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(keyAdapter, valueAdapter); return delegate.hashCode();
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj)
return true; return true;
if (obj == null || getClass() != obj.getClass()) if (obj == null || getClass() != obj.getClass())
return false; return false;
MapTypeAdapter<?, ?> that = MapTypeAdapter.class.cast(obj); MultimapTypeAdapter<?, ?> that = MultimapTypeAdapter.class.cast(obj);
return equal(this.keyAdapter, that.keyAdapter) && equal(this.valueAdapter, that.valueAdapter); return equal(this.delegate, that.delegate);
} }
@Override @Override
public String toString() { public String toString() {
return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString(); return toStringHelper(this).add("keyAdapter", delegate.keyAdapter)
} .add("valueAdapter", delegate.valueAdapter).toString();
} }
} }
@ -394,47 +419,5 @@ public class NullFilteringTypeAdapterFactories {
return (TypeAdapter<T>) new MultimapTypeAdapter<K, V>(keyAdapter, valueAdapter); return (TypeAdapter<T>) new MultimapTypeAdapter<K, V>(keyAdapter, valueAdapter);
} }
public static final class MultimapTypeAdapter<K, V> extends TypeAdapter<Multimap<K, V>> {
private final MapTypeAdapterFactory.MapTypeAdapter<K, Collection<V>> delegate;
public MultimapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
this.delegate = new MapTypeAdapterFactory.MapTypeAdapter<K, Collection<V>>(keyAdapter,
new CollectionTypeAdapterFactory.CollectionTypeAdapter<V>(valueAdapter));
nullSafe();
}
public void write(JsonWriter out, Multimap<K, V> value) throws IOException {
this.delegate.write(out, value.asMap());
}
public Multimap<K, V> read(JsonReader in) throws IOException {
ImmutableMultimap.Builder<K, V> builder = ImmutableMultimap.<K, V> builder();
for (Entry<K, Collection<V>> entry : delegate.read(in).entrySet())
builder.putAll(entry.getKey(), entry.getValue());
return builder.build();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
MultimapTypeAdapter<?, ?> that = MultimapTypeAdapter.class.cast(obj);
return equal(this.delegate, that.delegate);
}
@Override
public String toString() {
return toStringHelper(this).add("keyAdapter", delegate.keyAdapter)
.add("valueAdapter", delegate.valueAdapter).toString();
}
}
} }
} }

View File

@ -23,12 +23,16 @@ import static org.testng.Assert.assertEquals;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.CollectionTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.CollectionTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.FluentIterableTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.FluentIterableTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ImmutableListTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ImmutableSetTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.IterableTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ListTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MultimapTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MultimapTypeAdapterFactory;
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapterFactory; import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.SetTypeAdapterFactory;
@ -149,6 +153,46 @@ public class NullFilteringTypeAdapterFactoriesTest {
ImmutableList.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar"))); ImmutableList.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar")));
} }
private Gson list = new GsonBuilder().registerTypeAdapterFactory(new ListTypeAdapterFactory()).create();
private Type listType = new TypeToken<List<String>>() {
private static final long serialVersionUID = 1L;
}.getType();
private Type listResourceType = new TypeToken<List<Resource>>() {
private static final long serialVersionUID = 1L;
}.getType();
public void testList() {
Iterable<String> noNulls = list.fromJson("[\"value\",\"a test string!\"]", listType);
assertEquals(noNulls, ImmutableList.of("value", "a test string!"));
Iterable<String> withNull = list.fromJson("[null,\"a test string!\"]", listType);
assertEquals(withNull, ImmutableList.of("a test string!"));
Iterable<String> withDupes = list.fromJson("[\"value\",\"value\"]", listType);
assertEquals(withDupes, ImmutableList.of("value", "value"));
Iterable<Resource> resources = list.fromJson(
"[{\"id\":\"i-foo\",\"name\":\"foo\"},{\"id\":\"i-bar\",\"name\":\"bar\"}]", listResourceType);
assertEquals(resources, ImmutableList.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar")));
}
private Gson immutableList = new GsonBuilder().registerTypeAdapterFactory(new ImmutableListTypeAdapterFactory()).create();
private Type immutableListType = new TypeToken<ImmutableList<String>>() {
private static final long serialVersionUID = 1L;
}.getType();
private Type immutableListResourceType = new TypeToken<ImmutableList<Resource>>() {
private static final long serialVersionUID = 1L;
}.getType();
public void testImmutableList() {
Iterable<String> noNulls = immutableList.fromJson("[\"value\",\"a test string!\"]", immutableListType);
assertEquals(noNulls, ImmutableList.of("value", "a test string!"));
Iterable<String> withNull = immutableList.fromJson("[null,\"a test string!\"]", immutableListType);
assertEquals(withNull, ImmutableList.of("a test string!"));
Iterable<String> withDupes = immutableList.fromJson("[\"value\",\"value\"]", immutableListType);
assertEquals(withDupes, ImmutableList.of("value", "value"));
Iterable<Resource> resources = immutableList.fromJson(
"[{\"id\":\"i-foo\",\"name\":\"foo\"},{\"id\":\"i-bar\",\"name\":\"bar\"}]", immutableListResourceType);
assertEquals(resources, ImmutableList.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar")));
}
private Gson set = new GsonBuilder().registerTypeAdapterFactory(new SetTypeAdapterFactory()).create(); private Gson set = new GsonBuilder().registerTypeAdapterFactory(new SetTypeAdapterFactory()).create();
private Type setType = new TypeToken<Set<String>>() { private Type setType = new TypeToken<Set<String>>() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -169,6 +213,26 @@ public class NullFilteringTypeAdapterFactoriesTest {
assertEquals(resources, ImmutableSet.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar"))); assertEquals(resources, ImmutableSet.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar")));
} }
private Gson immutableSet = new GsonBuilder().registerTypeAdapterFactory(new ImmutableSetTypeAdapterFactory()).create();
private Type immutableSetType = new TypeToken<ImmutableSet<String>>() {
private static final long serialVersionUID = 1L;
}.getType();
private Type immutableSetResourceType = new TypeToken<ImmutableSet<Resource>>() {
private static final long serialVersionUID = 1L;
}.getType();
public void testImmutableSet() {
Iterable<String> noNulls = immutableSet.fromJson("[\"value\",\"a test string!\"]", immutableSetType);
assertEquals(noNulls, ImmutableSet.of("value", "a test string!"));
Iterable<String> withNull = immutableSet.fromJson("[null,\"a test string!\"]", immutableSetType);
assertEquals(withNull, ImmutableSet.of("a test string!"));
Iterable<String> withDupes = immutableSet.fromJson("[\"value\",\"value\"]", immutableSetType);
assertEquals(withDupes, ImmutableSet.of("value", "value"));
Iterable<Resource> resources = immutableSet.fromJson(
"[{\"id\":\"i-foo\",\"name\":\"foo\"},{\"id\":\"i-bar\",\"name\":\"bar\"}]", immutableSetResourceType);
assertEquals(resources, ImmutableSet.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar")));
}
private Gson map = new GsonBuilder().registerTypeAdapterFactory(new MapTypeAdapterFactory()).create(); private Gson map = new GsonBuilder().registerTypeAdapterFactory(new MapTypeAdapterFactory()).create();
private Type mapType = new TypeToken<Map<String, String>>() { private Type mapType = new TypeToken<Map<String, String>>() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;