mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 07:59:21 +08:00
Merge pull request #316 from square/jwilson.0526.delegate_core_adapter
Change the adapter for Object.class to delegate.
This commit is contained in:
@@ -20,6 +20,7 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -266,13 +267,45 @@ final class StandardJsonAdapters {
|
||||
*/
|
||||
static final class ObjectJsonAdapter extends JsonAdapter<Object> {
|
||||
private final Moshi moshi;
|
||||
private final JsonAdapter<List> listJsonAdapter;
|
||||
private final JsonAdapter<Map> mapAdapter;
|
||||
private final JsonAdapter<String> stringAdapter;
|
||||
private final JsonAdapter<Double> doubleAdapter;
|
||||
private final JsonAdapter<Boolean> booleanAdapter;
|
||||
|
||||
ObjectJsonAdapter(Moshi moshi) {
|
||||
this.moshi = moshi;
|
||||
this.listJsonAdapter = moshi.adapter(List.class);
|
||||
this.mapAdapter = moshi.adapter(Map.class);
|
||||
this.stringAdapter = moshi.adapter(String.class);
|
||||
this.doubleAdapter = moshi.adapter(Double.class);
|
||||
this.booleanAdapter = moshi.adapter(Boolean.class);
|
||||
}
|
||||
|
||||
@Override public Object fromJson(JsonReader reader) throws IOException {
|
||||
return reader.readJsonValue();
|
||||
switch (reader.peek()) {
|
||||
case BEGIN_ARRAY:
|
||||
return listJsonAdapter.fromJson(reader);
|
||||
|
||||
case BEGIN_OBJECT:
|
||||
return mapAdapter.fromJson(reader);
|
||||
|
||||
case STRING:
|
||||
return stringAdapter.fromJson(reader);
|
||||
|
||||
case NUMBER:
|
||||
return doubleAdapter.fromJson(reader);
|
||||
|
||||
case BOOLEAN:
|
||||
return booleanAdapter.fromJson(reader);
|
||||
|
||||
case NULL:
|
||||
return reader.nextNull();
|
||||
|
||||
default:
|
||||
throw new IllegalStateException(
|
||||
"Expected a value but was " + reader.peek() + " at path " + reader.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void toJson(JsonWriter writer, Object value) throws IOException {
|
||||
|
@@ -15,6 +15,10 @@
|
||||
*/
|
||||
package com.squareup.moshi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.AbstractList;
|
||||
import java.util.AbstractMap;
|
||||
@@ -26,12 +30,17 @@ import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
public final class ObjectAdapterTest {
|
||||
@Test public void toJsonUsesRuntimeType() throws Exception {
|
||||
@@ -170,6 +179,107 @@ public final class ObjectAdapterTest {
|
||||
assertThat(adapter.toJson(Arrays.asList(new Date(1), new Date(2)))).isEqualTo("[1,2]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that the built-in adapter for Object delegates to user-supplied adapters for JSON value
|
||||
* types like strings.
|
||||
*/
|
||||
@Test public void objectAdapterDelegatesStringNamesAndValues() throws Exception {
|
||||
JsonAdapter<String> stringAdapter = new JsonAdapter<String>() {
|
||||
@Nullable @Override public String fromJson(JsonReader reader) throws IOException {
|
||||
return reader.nextString().toUpperCase(Locale.US);
|
||||
}
|
||||
|
||||
@Override public void toJson(JsonWriter writer, @Nullable String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(String.class, stringAdapter)
|
||||
.build();
|
||||
JsonAdapter<Object> objectAdapter = moshi.adapter(Object.class);
|
||||
Map<?, ?> value = (Map<?, ?>) objectAdapter.fromJson("{\"a\":\"b\", \"c\":\"d\"}");
|
||||
assertThat(value).containsExactly(entry("A", "B"), entry("C", "D"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that the built-in adapter for Object delegates to any user-supplied adapters for
|
||||
* Object. This is necessary to customize adapters for primitives like numbers.
|
||||
*/
|
||||
@Test public void objectAdapterDelegatesObjects() throws Exception {
|
||||
JsonAdapter.Factory objectFactory = new JsonAdapter.Factory() {
|
||||
@Override public @Nullable JsonAdapter<?> create(
|
||||
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||
if (type != Object.class) return null;
|
||||
|
||||
final JsonAdapter<Object> delegate = moshi.nextAdapter(this, Object.class, annotations);
|
||||
return new JsonAdapter<Object>() {
|
||||
@Override public @Nullable Object fromJson(JsonReader reader) throws IOException {
|
||||
if (reader.peek() != JsonReader.Token.NUMBER) {
|
||||
return delegate.fromJson(reader);
|
||||
} else {
|
||||
return new BigDecimal(reader.nextString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void toJson(JsonWriter writer, @Nullable Object value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(objectFactory)
|
||||
.build();
|
||||
JsonAdapter<Object> objectAdapter = moshi.adapter(Object.class);
|
||||
List<?> value = (List<?>) objectAdapter.fromJson("[0, 1, 2.0, 3.14]");
|
||||
assertThat(value).isEqualTo(Arrays.asList(new BigDecimal("0"), new BigDecimal("1"),
|
||||
new BigDecimal("2.0"), new BigDecimal("3.14")));
|
||||
}
|
||||
|
||||
/** Confirm that the built-in adapter for Object delegates to user-supplied adapters for lists. */
|
||||
@Test public void objectAdapterDelegatesLists() throws Exception {
|
||||
JsonAdapter<List<?>> listAdapter = new JsonAdapter<List<?>>() {
|
||||
@Override public @Nullable List<?> fromJson(JsonReader reader) throws IOException {
|
||||
reader.skipValue();
|
||||
return singletonList("z");
|
||||
}
|
||||
|
||||
@Override public void toJson(JsonWriter writer, @Nullable List<?> value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(List.class, listAdapter)
|
||||
.build();
|
||||
JsonAdapter<Object> objectAdapter = moshi.adapter(Object.class);
|
||||
Map<?, ?> mapOfList = (Map<?, ?>) objectAdapter.fromJson("{\"a\":[\"b\"]}");
|
||||
assertThat(mapOfList).isEqualTo(singletonMap("a", singletonList("z")));
|
||||
}
|
||||
|
||||
/** Confirm that the built-in adapter for Object delegates to user-supplied adapters for maps. */
|
||||
@Test public void objectAdapterDelegatesMaps() throws Exception {
|
||||
JsonAdapter<Map<?, ?>> mapAdapter = new JsonAdapter<Map<?, ?>>() {
|
||||
@Override public @Nullable Map<?, ?> fromJson(JsonReader reader) throws IOException {
|
||||
reader.skipValue();
|
||||
return singletonMap("x", "y");
|
||||
}
|
||||
|
||||
@Override public void toJson(JsonWriter writer, @Nullable Map<?, ?> value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
Moshi moshi = new Moshi.Builder()
|
||||
.add(Map.class, mapAdapter)
|
||||
.build();
|
||||
JsonAdapter<Object> objectAdapter = moshi.adapter(Object.class);
|
||||
List<?> listOfMap = (List<?>) objectAdapter.fromJson("[{\"b\":\"c\"}]");
|
||||
assertThat(listOfMap).isEqualTo(singletonList(singletonMap("x", "y")));
|
||||
}
|
||||
|
||||
static class Delivery {
|
||||
String address;
|
||||
List<Object> items;
|
||||
|
Reference in New Issue
Block a user