mirror of https://github.com/apache/jclouds.git
make it possible to deserialize into ctors that have immutable collection parameters
This commit is contained in:
parent
7596205774
commit
ef2718629f
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,33 +62,6 @@ public class NullFilteringTypeAdapterFactories {
|
||||||
param));
|
param));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class IterableTypeAdapterFactory implements TypeAdapterFactory {
|
|
||||||
|
|
||||||
protected final Class<?> declaring;
|
|
||||||
|
|
||||||
public IterableTypeAdapterFactory() {
|
|
||||||
this(Iterable.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IterableTypeAdapterFactory(Class<?> declaring) {
|
|
||||||
this.declaring = declaring;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> ownerType) {
|
|
||||||
Type type = ownerType.getType();
|
|
||||||
if (ownerType.getRawType() != declaring || !(type instanceof ParameterizedType))
|
|
||||||
return null;
|
|
||||||
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
|
||||||
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
|
||||||
return (TypeAdapter<T>) newAdapter(elementAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
|
|
||||||
return (TypeAdapter<I>) new IterableTypeAdapter<E>(elementAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class IterableTypeAdapter<E> extends TypeAdapter<Iterable<E>> {
|
public static final class IterableTypeAdapter<E> extends TypeAdapter<Iterable<E>> {
|
||||||
|
|
||||||
private final TypeAdapter<E> elementAdapter;
|
private final TypeAdapter<E> elementAdapter;
|
||||||
|
@ -145,73 +119,60 @@ public class NullFilteringTypeAdapterFactories {
|
||||||
return toStringHelper(this).add("elementAdapter", elementAdapter).toString();
|
return toStringHelper(this).add("elementAdapter", elementAdapter).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ImmutableListTypeAdapterFactory implements TypeAdapterFactory {
|
||||||
|
|
||||||
|
protected final Class<?> declaring;
|
||||||
|
|
||||||
|
public ImmutableListTypeAdapterFactory() {
|
||||||
|
this(ImmutableList.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CollectionTypeAdapterFactory extends IterableTypeAdapterFactory {
|
protected ImmutableListTypeAdapterFactory(Class<?> declaring) {
|
||||||
|
this.declaring = declaring;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> ownerType) {
|
||||||
|
Type type = ownerType.getType();
|
||||||
|
if (ownerType.getRawType() != declaring || !(type instanceof ParameterizedType))
|
||||||
|
return null;
|
||||||
|
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
|
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
||||||
|
return (TypeAdapter<T>) newAdapter(elementAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
|
||||||
|
return (TypeAdapter<I>) new IterableTypeAdapter<E>(elementAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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")
|
|
||||||
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
|
|
||||||
return (TypeAdapter<I>) new CollectionTypeAdapter<E>(elementAdapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
public static class ListTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
|
||||||
|
public ListTypeAdapterFactory() {
|
||||||
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate;
|
super(List.class);
|
||||||
|
|
||||||
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 SetTypeAdapterFactory() {
|
|
||||||
super(Set.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
|
|
||||||
return (TypeAdapter<I>) new SetTypeAdapter<E>(elementAdapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class SetTypeAdapter<E> extends TypeAdapter<Set<E>> {
|
public static final class SetTypeAdapter<E> extends TypeAdapter<Set<E>> {
|
||||||
|
|
||||||
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate;
|
private final IterableTypeAdapter<E> delegate;
|
||||||
|
|
||||||
public SetTypeAdapter(TypeAdapter<E> elementAdapter) {
|
public SetTypeAdapter(TypeAdapter<E> elementAdapter) {
|
||||||
this.delegate = new IterableTypeAdapterFactory.IterableTypeAdapter<E>(elementAdapter);
|
this.delegate = new IterableTypeAdapter<E>(elementAdapter);
|
||||||
nullSafe();
|
nullSafe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,24 +204,34 @@ public class NullFilteringTypeAdapterFactories {
|
||||||
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
|
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ImmutableSetTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
|
||||||
|
public ImmutableSetTypeAdapterFactory() {
|
||||||
|
this(ImmutableSet.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FluentIterableTypeAdapterFactory extends IterableTypeAdapterFactory {
|
protected ImmutableSetTypeAdapterFactory(Class<?> declaring) {
|
||||||
public FluentIterableTypeAdapterFactory() {
|
super(declaring);
|
||||||
super(FluentIterable.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@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 FluentIterableTypeAdapter<E>(elementAdapter);
|
return (TypeAdapter<I>) new SetTypeAdapter<E>(elementAdapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class FluentIterableTypeAdapter<E> extends TypeAdapter<FluentIterable<E>> {
|
public static class SetTypeAdapterFactory extends ImmutableSetTypeAdapterFactory {
|
||||||
|
public SetTypeAdapterFactory() {
|
||||||
|
super(Set.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final IterableTypeAdapterFactory.IterableTypeAdapter<E> delegate;
|
private static final class FluentIterableTypeAdapter<E> extends TypeAdapter<FluentIterable<E>> {
|
||||||
|
|
||||||
|
private final IterableTypeAdapter<E> delegate;
|
||||||
|
|
||||||
public FluentIterableTypeAdapter(TypeAdapter<E> elementAdapter) {
|
public FluentIterableTypeAdapter(TypeAdapter<E> elementAdapter) {
|
||||||
this.delegate = new IterableTypeAdapterFactory.IterableTypeAdapter<E>(elementAdapter);
|
this.delegate = new IterableTypeAdapter<E>(elementAdapter);
|
||||||
nullSafe();
|
nullSafe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,37 +263,19 @@ public class NullFilteringTypeAdapterFactories {
|
||||||
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
|
return toStringHelper(this).add("elementAdapter", delegate.elementAdapter).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static class MapTypeAdapterFactory implements TypeAdapterFactory {
|
public static class FluentIterableTypeAdapterFactory extends ImmutableListTypeAdapterFactory {
|
||||||
|
public FluentIterableTypeAdapterFactory() {
|
||||||
protected final Class<?> declaring;
|
super(FluentIterable.class);
|
||||||
|
|
||||||
public MapTypeAdapterFactory() {
|
|
||||||
this(Map.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected MapTypeAdapterFactory(Class<?> declaring) {
|
|
||||||
this.declaring = declaring;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> ownerType) {
|
|
||||||
Type type = ownerType.getType();
|
|
||||||
if (ownerType.getRawType() != declaring || !(type instanceof ParameterizedType))
|
|
||||||
return null;
|
|
||||||
Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
|
||||||
Type valueType = ((ParameterizedType) type).getActualTypeArguments()[1];
|
|
||||||
TypeAdapter<?> keyAdapter = gson.getAdapter(TypeToken.get(keyType));
|
|
||||||
TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(valueType));
|
|
||||||
return newAdapter(keyAdapter, valueAdapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected <K, V, T> TypeAdapter<T> newAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
|
protected <E, I> TypeAdapter<I> newAdapter(TypeAdapter<E> elementAdapter) {
|
||||||
return (TypeAdapter<T>) new MapTypeAdapter<K, V>(keyAdapter, valueAdapter);
|
return (TypeAdapter<I>) new FluentIterableTypeAdapter<E>(elementAdapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
|
private static final class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
|
||||||
|
|
||||||
protected final TypeAdapter<K> keyAdapter;
|
protected final TypeAdapter<K> keyAdapter;
|
||||||
protected final TypeAdapter<V> valueAdapter;
|
protected final TypeAdapter<V> valueAdapter;
|
||||||
|
@ -380,37 +333,54 @@ public class NullFilteringTypeAdapterFactories {
|
||||||
return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString();
|
return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MapTypeAdapterFactory implements TypeAdapterFactory {
|
||||||
|
|
||||||
|
protected final Class<?> declaring;
|
||||||
|
|
||||||
|
public MapTypeAdapterFactory() {
|
||||||
|
this(Map.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MultimapTypeAdapterFactory extends MapTypeAdapterFactory {
|
protected MapTypeAdapterFactory(Class<?> declaring) {
|
||||||
|
this.declaring = declaring;
|
||||||
|
}
|
||||||
|
|
||||||
public MultimapTypeAdapterFactory() {
|
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> ownerType) {
|
||||||
super(Multimap.class);
|
Type type = ownerType.getType();
|
||||||
|
if (ownerType.getRawType() != declaring || !(type instanceof ParameterizedType))
|
||||||
|
return null;
|
||||||
|
Type keyType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
|
Type valueType = ((ParameterizedType) type).getActualTypeArguments()[1];
|
||||||
|
TypeAdapter<?> keyAdapter = gson.getAdapter(TypeToken.get(keyType));
|
||||||
|
TypeAdapter<?> valueAdapter = gson.getAdapter(TypeToken.get(valueType));
|
||||||
|
return newAdapter(keyAdapter, valueAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
|
||||||
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 MultimapTypeAdapter<K, V>(keyAdapter, valueAdapter);
|
return (TypeAdapter<T>) new MapTypeAdapter<K, V>(keyAdapter, valueAdapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class MultimapTypeAdapter<K, V> extends TypeAdapter<Multimap<K, V>> {
|
private static final class MultimapTypeAdapter<K, V> extends TypeAdapter<Multimap<K, V>> {
|
||||||
|
|
||||||
private final MapTypeAdapterFactory.MapTypeAdapter<K, Collection<V>> delegate;
|
private final MapTypeAdapter<K, Iterable<V>> delegate;
|
||||||
|
|
||||||
public MultimapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
|
public MultimapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
|
||||||
this.delegate = new MapTypeAdapterFactory.MapTypeAdapter<K, Collection<V>>(keyAdapter,
|
this.delegate = new MapTypeAdapter<K, Iterable<V>>(keyAdapter,
|
||||||
new CollectionTypeAdapterFactory.CollectionTypeAdapter<V>(valueAdapter));
|
new IterableTypeAdapter<V>(valueAdapter));
|
||||||
nullSafe();
|
nullSafe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public void write(JsonWriter out, Multimap<K, V> value) throws IOException {
|
public void write(JsonWriter out, Multimap<K, V> value) throws IOException {
|
||||||
this.delegate.write(out, value.asMap());
|
this.delegate.write(out, Map.class.cast(value.asMap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Multimap<K, V> read(JsonReader in) throws IOException {
|
public Multimap<K, V> read(JsonReader in) throws IOException {
|
||||||
ImmutableMultimap.Builder<K, V> builder = ImmutableMultimap.<K, V> builder();
|
ImmutableMultimap.Builder<K, V> builder = ImmutableMultimap.<K, V> builder();
|
||||||
for (Entry<K, Collection<V>> entry : delegate.read(in).entrySet())
|
for (Entry<K, Iterable<V>> entry : delegate.read(in).entrySet())
|
||||||
builder.putAll(entry.getKey(), entry.getValue());
|
builder.putAll(entry.getKey(), entry.getValue());
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
@ -436,5 +406,18 @@ public class NullFilteringTypeAdapterFactories {
|
||||||
.add("valueAdapter", delegate.valueAdapter).toString();
|
.add("valueAdapter", delegate.valueAdapter).toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class MultimapTypeAdapterFactory extends MapTypeAdapterFactory {
|
||||||
|
|
||||||
|
public MultimapTypeAdapterFactory() {
|
||||||
|
super(Multimap.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
protected <K, V, T> TypeAdapter<T> newAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
|
||||||
|
return (TypeAdapter<T>) new MultimapTypeAdapter<K, V>(keyAdapter, valueAdapter);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue