mirror of
https://github.com/fankes/moshi.git
synced 2025-10-22 01:19:22 +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.lang.reflect.Type;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
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;
|
||||||
|
|
||||||
@@ -266,13 +267,45 @@ final class StandardJsonAdapters {
|
|||||||
*/
|
*/
|
||||||
static final class ObjectJsonAdapter extends JsonAdapter<Object> {
|
static final class ObjectJsonAdapter extends JsonAdapter<Object> {
|
||||||
private final Moshi moshi;
|
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) {
|
ObjectJsonAdapter(Moshi moshi) {
|
||||||
this.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 {
|
@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 {
|
@Override public void toJson(JsonWriter writer, Object value) throws IOException {
|
||||||
|
@@ -15,6 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.squareup.moshi;
|
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.AbstractCollection;
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
@@ -26,12 +30,17 @@ import java.util.Date;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
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.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.entry;
|
||||||
|
|
||||||
public final class ObjectAdapterTest {
|
public final class ObjectAdapterTest {
|
||||||
@Test public void toJsonUsesRuntimeType() throws Exception {
|
@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]");
|
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 {
|
static class Delivery {
|
||||||
String address;
|
String address;
|
||||||
List<Object> items;
|
List<Object> items;
|
||||||
|
Reference in New Issue
Block a user