mirror of https://github.com/apache/jclouds.git
JCLOUDS-1044 fix handling NULL JsonTokens in adapters under NullFilteringTypeAdapterFactories class
This commit is contained in:
parent
4d899cacae
commit
0fb1b459a6
|
@ -16,8 +16,6 @@
|
|||
*/
|
||||
package org.jclouds.chef.config;
|
||||
|
||||
import static com.google.common.base.Objects.equal;
|
||||
import static com.google.common.base.Objects.toStringHelper;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
|
@ -39,11 +37,11 @@ import org.jclouds.crypto.Crypto;
|
|||
import org.jclouds.crypto.Pems;
|
||||
import org.jclouds.json.config.GsonModule.DateAdapter;
|
||||
import org.jclouds.json.config.GsonModule.Iso8601DateAdapter;
|
||||
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories;
|
||||
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.MapTypeAdapterFactory;
|
||||
import org.jclouds.json.internal.NullHackJsonLiteralAdapter;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
@ -57,7 +55,7 @@ import com.google.gson.JsonSyntaxException;
|
|||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.internal.JsonReaderInternalAccess;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.ImplementedBy;
|
||||
import com.google.inject.Provides;
|
||||
|
@ -205,33 +203,19 @@ public class ChefParserModule extends AbstractModule {
|
|||
private String id;
|
||||
}
|
||||
|
||||
// The NullFilteringTypeAdapterFactories.MapTypeAdapter class is final. Do
|
||||
// the same logic here
|
||||
private static final class KeepLastRepeatedKeyMapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
|
||||
|
||||
protected final TypeAdapter<K> keyAdapter;
|
||||
protected final TypeAdapter<V> valueAdapter;
|
||||
private static final class KeepLastRepeatedKeyMapTypeAdapter<K, V>
|
||||
extends NullFilteringTypeAdapterFactories.MapTypeAdapter<K, V> {
|
||||
|
||||
protected KeepLastRepeatedKeyMapTypeAdapter(TypeAdapter<K> keyAdapter, TypeAdapter<V> valueAdapter) {
|
||||
this.keyAdapter = keyAdapter;
|
||||
this.valueAdapter = valueAdapter;
|
||||
nullSafe();
|
||||
}
|
||||
|
||||
public void write(JsonWriter out, Map<K, V> value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
out.beginObject();
|
||||
for (Map.Entry<K, V> element : value.entrySet()) {
|
||||
out.name(String.valueOf(element.getKey()));
|
||||
valueAdapter.write(out, element.getValue());
|
||||
}
|
||||
out.endObject();
|
||||
super(keyAdapter, valueAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<K, V> read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
Map<K, V> result = Maps.newHashMap();
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
|
@ -239,33 +223,14 @@ public class ChefParserModule extends AbstractModule {
|
|||
K name = keyAdapter.read(in);
|
||||
V value = valueAdapter.read(in);
|
||||
if (value != null) {
|
||||
// If there are repeated keys, overwrite them to only keep the last one
|
||||
// If there are repeated keys, overwrite them to only keep the
|
||||
// last one
|
||||
result.put(name, value);
|
||||
}
|
||||
}
|
||||
in.endObject();
|
||||
return ImmutableMap.copyOf(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(keyAdapter, valueAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null || getClass() != obj.getClass())
|
||||
return false;
|
||||
KeepLastRepeatedKeyMapTypeAdapter<?, ?> that = KeepLastRepeatedKeyMapTypeAdapter.class.cast(obj);
|
||||
return equal(this.keyAdapter, that.keyAdapter) && equal(this.valueAdapter, that.valueAdapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toStringHelper(this).add("keyAdapter", keyAdapter).add("valueAdapter", valueAdapter).toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static class KeepLastRepeatedKeyMapTypeAdapterFactory extends MapTypeAdapterFactory {
|
||||
|
|
|
@ -20,12 +20,15 @@ import static com.google.common.base.Objects.equal;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jclouds.chef.config.ChefParserModule.KeepLastRepeatedKeyMapTypeAdapterFactory;
|
||||
import org.jclouds.json.internal.NullFilteringTypeAdapterFactories.ListTypeAdapterFactory;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import com.google.gson.Gson;
|
||||
|
@ -90,4 +93,25 @@ public class ChefParserModuleTest {
|
|||
assertEquals(duplicates,
|
||||
ImmutableMap.of("i-foo", new KeyValue("i-foo", "foo2"), "i-bar", new KeyValue("i-bar", "bar2")));
|
||||
}
|
||||
|
||||
private Gson listInMap = new GsonBuilder().registerTypeAdapterFactory(new KeepLastRepeatedKeyMapTypeAdapterFactory())
|
||||
.registerTypeAdapterFactory(new ListTypeAdapterFactory()).create();
|
||||
private Type listInMapType = new TypeToken<Map<String, List<Map<String, String>>>>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}.getType();
|
||||
|
||||
public void testListInMap() {
|
||||
Map<String, List<Map<String, String>>> notNull = listInMap
|
||||
.fromJson("{\"value\":[{\"x\":\"y\",\"a\":\"b\"},{\"u\":\"v\"}]}", listInMapType);
|
||||
assertEquals(notNull,
|
||||
ImmutableMap.of("value", ImmutableList.of(ImmutableMap.of("x", "y", "a", "b"), ImmutableMap.of("u", "v"))));
|
||||
Map<String, List<Map<String, String>>> innerMapValueNull = listInMap
|
||||
.fromJson("{\"value\":[{\"x\":\"y\",\"a\":null},{\"u\":\"v\"}]}", listInMapType);
|
||||
assertEquals(innerMapValueNull,
|
||||
ImmutableMap.of("value", ImmutableList.of(ImmutableMap.of("x", "y"), ImmutableMap.of("u", "v"))));
|
||||
Map<String, List<Map<String, String>>> withNullInList = listInMap.fromJson("{\"value\":[null]}", listInMapType);
|
||||
assertEquals(withNullInList, ImmutableMap.of("value", ImmutableList.of()));
|
||||
Map<String, List<Map<String, String>>> withNullAsList = listInMap.fromJson("{\"parent\":null}", listInMapType);
|
||||
assertEquals(withNullAsList, ImmutableMap.of());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.google.gson.TypeAdapterFactory;
|
|||
import com.google.gson.internal.JsonReaderInternalAccess;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -85,6 +86,10 @@ public class NullFilteringTypeAdapterFactories {
|
|||
@SuppressWarnings("unchecked")
|
||||
protected <C extends Iterable<E>, B extends ImmutableCollection.Builder<E>> C readAndBuild(JsonReader in,
|
||||
B builder) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
in.beginArray();
|
||||
while (in.hasNext()) {
|
||||
E element = elementAdapter.read(in);
|
||||
|
@ -278,7 +283,7 @@ public class NullFilteringTypeAdapterFactories {
|
|||
}
|
||||
}
|
||||
|
||||
private static final class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
|
||||
public static class MapTypeAdapter<K, V> extends TypeAdapter<Map<K, V>> {
|
||||
|
||||
protected final TypeAdapter<K> keyAdapter;
|
||||
protected final TypeAdapter<V> valueAdapter;
|
||||
|
@ -303,6 +308,10 @@ public class NullFilteringTypeAdapterFactories {
|
|||
}
|
||||
|
||||
public Map<K, V> read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
ImmutableMap.Builder<K, V> result = ImmutableMap.builder();
|
||||
in.beginObject();
|
||||
while (in.hasNext()) {
|
||||
|
|
|
@ -297,4 +297,25 @@ public class NullFilteringTypeAdapterFactoriesTest {
|
|||
assertEquals(resourceDupes.get("i-foo"),
|
||||
ImmutableList.of(new Resource("i-foo", "foo"), new Resource("i-bar", "bar")));
|
||||
}
|
||||
|
||||
private Gson listInMap = new GsonBuilder().registerTypeAdapterFactory(new MapTypeAdapterFactory())
|
||||
.registerTypeAdapterFactory(new ListTypeAdapterFactory()).create();
|
||||
private Type listInMapType = new TypeToken<Map<String, List<Map<String, String>>>>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
}.getType();
|
||||
|
||||
public void testListInMap() {
|
||||
Map<String, List<Map<String, String>>> notNull = listInMap
|
||||
.fromJson("{\"value\":[{\"x\":\"y\",\"a\":\"b\"},{\"u\":\"v\"}]}", listInMapType);
|
||||
assertEquals(notNull,
|
||||
ImmutableMap.of("value", ImmutableList.of(ImmutableMap.of("x", "y", "a", "b"), ImmutableMap.of("u", "v"))));
|
||||
Map<String, List<Map<String, String>>> innerMapValueNull = listInMap
|
||||
.fromJson("{\"value\":[{\"x\":\"y\",\"a\":null},{\"u\":\"v\"}]}", listInMapType);
|
||||
assertEquals(innerMapValueNull,
|
||||
ImmutableMap.of("value", ImmutableList.of(ImmutableMap.of("x", "y"), ImmutableMap.of("u", "v"))));
|
||||
Map<String, List<Map<String, String>>> withNullInList = listInMap.fromJson("{\"value\":[null]}", listInMapType);
|
||||
assertEquals(withNullInList, ImmutableMap.of("value", ImmutableList.of()));
|
||||
Map<String, List<Map<String, String>>> withNullAsList = listInMap.fromJson("{\"parent\":null}", listInMapType);
|
||||
assertEquals(withNullAsList, ImmutableMap.of());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue