mirror of
https://github.com/fankes/moshi.git
synced 2025-10-19 16:09:21 +08:00
New @JsonQualifier annotation.
Works like JSR-330's @Qualifier annotation. You may have multiple qualifiers, or none.
This commit is contained in:
@@ -16,29 +16,30 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
// TODO: support qualifier annotations.
|
|
||||||
// TODO: support @Nullable
|
// TODO: support @Nullable
|
||||||
// TODO: path in JsonWriter.
|
// TODO: path in JsonWriter.
|
||||||
|
|
||||||
final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
||||||
private final Map<Type, ToAdapter> toAdapters;
|
private final List<AdapterMethod> toAdapters;
|
||||||
private final Map<Type, FromAdapter> fromAdapters;
|
private final List<AdapterMethod> fromAdapters;
|
||||||
|
|
||||||
AdapterMethodsFactory(Map<Type, ToAdapter> toAdapters, Map<Type, FromAdapter> fromAdapters) {
|
public AdapterMethodsFactory(List<AdapterMethod> toAdapters, List<AdapterMethod> fromAdapters) {
|
||||||
this.toAdapters = toAdapters;
|
this.toAdapters = toAdapters;
|
||||||
this.fromAdapters = fromAdapters;
|
this.fromAdapters = fromAdapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, final Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
final ToAdapter toAdapter = toAdapters.get(type);
|
Type type, Set<? extends Annotation> annotations, final Moshi moshi) {
|
||||||
final FromAdapter fromAdapter = fromAdapters.get(type);
|
final AdapterMethod toAdapter = get(toAdapters, type, annotations);
|
||||||
|
final AdapterMethod fromAdapter = get(fromAdapters, type, annotations);
|
||||||
if (toAdapter == null && fromAdapter == null) return null;
|
if (toAdapter == null && fromAdapter == null) return null;
|
||||||
|
|
||||||
final JsonAdapter<Object> delegate = toAdapter == null || fromAdapter == null
|
final JsonAdapter<Object> delegate = toAdapter == null || fromAdapter == null
|
||||||
@@ -56,7 +57,7 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof IOException) throw (IOException) e.getCause();
|
if (e.getCause() instanceof IOException) throw (IOException) e.getCause();
|
||||||
throw new JsonDataException(e.getCause().getMessage()); // TODO: more context?
|
throw new JsonDataException(e.getCause()); // TODO: more context?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,7 +72,7 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
if (e.getCause() instanceof IOException) throw (IOException) e.getCause();
|
if (e.getCause() instanceof IOException) throw (IOException) e.getCause();
|
||||||
throw new JsonDataException(e.getCause().getMessage()); // TODO: more context?
|
throw new JsonDataException(e.getCause()); // TODO: more context?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,29 +80,31 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static AdapterMethodsFactory get(Object adapter) {
|
public static AdapterMethodsFactory get(Object adapter) {
|
||||||
Map<Type, ToAdapter> toAdapters = new LinkedHashMap<>();
|
List<AdapterMethod> toAdapters = new ArrayList<>();
|
||||||
Map<Type, FromAdapter> fromAdapters = new LinkedHashMap<>();
|
List<AdapterMethod> fromAdapters = new ArrayList<>();
|
||||||
|
|
||||||
for (Class<?> c = adapter.getClass(); c != Object.class; c = c.getSuperclass()) {
|
for (Class<?> c = adapter.getClass(); c != Object.class; c = c.getSuperclass()) {
|
||||||
for (Method m : c.getDeclaredMethods()) {
|
for (Method m : c.getDeclaredMethods()) {
|
||||||
if (m.isAnnotationPresent(ToJson.class)) {
|
if (m.isAnnotationPresent(ToJson.class)) {
|
||||||
ToAdapter toAdapter = toAdapter(adapter, m);
|
AdapterMethod toAdapter = toAdapter(adapter, m);
|
||||||
ToAdapter replaced = toAdapters.put(toAdapter.type, toAdapter);
|
AdapterMethod conflicting = get(toAdapters, toAdapter.type, toAdapter.annotations);
|
||||||
if (replaced != null) {
|
if (conflicting != null) {
|
||||||
throw new IllegalArgumentException("Conflicting @ToJson methods:\n"
|
throw new IllegalArgumentException("Conflicting @ToJson methods:\n"
|
||||||
+ " " + replaced.method + "\n"
|
+ " " + conflicting.method + "\n"
|
||||||
+ " " + toAdapter.method);
|
+ " " + toAdapter.method);
|
||||||
}
|
}
|
||||||
|
toAdapters.add(toAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m.isAnnotationPresent(FromJson.class)) {
|
if (m.isAnnotationPresent(FromJson.class)) {
|
||||||
FromAdapter fromAdapter = fromAdapter(adapter, m);
|
AdapterMethod fromAdapter = fromAdapter(adapter, m);
|
||||||
FromAdapter replaced = fromAdapters.put(fromAdapter.type, fromAdapter);
|
AdapterMethod conflicting = get(fromAdapters, fromAdapter.type, fromAdapter.annotations);
|
||||||
if (replaced != null) {
|
if (conflicting != null) {
|
||||||
throw new IllegalArgumentException("Conflicting @FromJson methods:\n"
|
throw new IllegalArgumentException("Conflicting @FromJson methods:\n"
|
||||||
+ " " + replaced.method + "\n"
|
+ " " + conflicting.method + "\n"
|
||||||
+ " " + fromAdapter.method);
|
+ " " + fromAdapter.method);
|
||||||
}
|
}
|
||||||
|
fromAdapters.add(fromAdapter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,7 +121,7 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
* Returns an object that calls a {@code method} method on {@code adapter} in service of
|
* Returns an object that calls a {@code method} method on {@code adapter} in service of
|
||||||
* converting an object to JSON.
|
* converting an object to JSON.
|
||||||
*/
|
*/
|
||||||
static ToAdapter toAdapter(Object adapter, Method method) {
|
static AdapterMethod toAdapter(Object adapter, Method method) {
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
Type[] parameterTypes = method.getGenericParameterTypes();
|
Type[] parameterTypes = method.getGenericParameterTypes();
|
||||||
final Type returnType = method.getGenericReturnType();
|
final Type returnType = method.getGenericReturnType();
|
||||||
@@ -126,7 +129,10 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
if (parameterTypes.length == 2
|
if (parameterTypes.length == 2
|
||||||
&& parameterTypes[0] == JsonWriter.class
|
&& parameterTypes[0] == JsonWriter.class
|
||||||
&& returnType == void.class) {
|
&& returnType == void.class) {
|
||||||
return new ToAdapter(parameterTypes[1], adapter, method) {
|
// public void pointToJson(JsonWriter jsonWriter, Point point) throws Exception {
|
||||||
|
Set<? extends Annotation> parameterAnnotations
|
||||||
|
= Util.jsonAnnotations(method.getParameterAnnotations()[1]);
|
||||||
|
return new AdapterMethod(parameterTypes[1], parameterAnnotations, adapter, method) {
|
||||||
@Override public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
@Override public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
||||||
throws IOException, InvocationTargetException, IllegalAccessException {
|
throws IOException, InvocationTargetException, IllegalAccessException {
|
||||||
method.invoke(adapter, writer, value);
|
method.invoke(adapter, writer, value);
|
||||||
@@ -134,10 +140,14 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} else if (parameterTypes.length == 1 && returnType != void.class) {
|
} else if (parameterTypes.length == 1 && returnType != void.class) {
|
||||||
return new ToAdapter(parameterTypes[0], adapter, method) {
|
// public List<Integer> pointToJson(Point point) throws Exception {
|
||||||
|
final Set<? extends Annotation> returnTypeAnnotations = Util.jsonAnnotations(method);
|
||||||
|
Set<? extends Annotation> parameterAnnotations =
|
||||||
|
Util.jsonAnnotations(method.getParameterAnnotations()[0]);
|
||||||
|
return new AdapterMethod(parameterTypes[0], parameterAnnotations, adapter, method) {
|
||||||
@Override public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
@Override public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
||||||
throws IOException, InvocationTargetException, IllegalAccessException {
|
throws IOException, InvocationTargetException, IllegalAccessException {
|
||||||
JsonAdapter<Object> delegate = moshi.adapter(returnType, method);
|
JsonAdapter<Object> delegate = moshi.adapter(returnType, returnTypeAnnotations);
|
||||||
Object intermediate = method.invoke(adapter, value);
|
Object intermediate = method.invoke(adapter, value);
|
||||||
delegate.toJson(writer, intermediate);
|
delegate.toJson(writer, intermediate);
|
||||||
}
|
}
|
||||||
@@ -151,26 +161,11 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static abstract class ToAdapter {
|
|
||||||
final Type type;
|
|
||||||
final Object adapter;
|
|
||||||
final Method method;
|
|
||||||
|
|
||||||
public ToAdapter(Type type, Object adapter, Method method) {
|
|
||||||
this.type = type;
|
|
||||||
this.adapter = adapter;
|
|
||||||
this.method = method;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void toJson(Moshi moshi, JsonWriter writer, Object value)
|
|
||||||
throws IOException, IllegalAccessException, InvocationTargetException;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object that calls a {@code method} method on {@code adapter} in service of
|
* Returns an object that calls a {@code method} method on {@code adapter} in service of
|
||||||
* converting an object from JSON.
|
* converting an object from JSON.
|
||||||
*/
|
*/
|
||||||
static FromAdapter fromAdapter(Object adapter, Method method) {
|
static AdapterMethod fromAdapter(Object adapter, Method method) {
|
||||||
method.setAccessible(true);
|
method.setAccessible(true);
|
||||||
final Type[] parameterTypes = method.getGenericParameterTypes();
|
final Type[] parameterTypes = method.getGenericParameterTypes();
|
||||||
final Type returnType = method.getGenericReturnType();
|
final Type returnType = method.getGenericReturnType();
|
||||||
@@ -179,7 +174,8 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
&& parameterTypes[0] == JsonReader.class
|
&& parameterTypes[0] == JsonReader.class
|
||||||
&& returnType != void.class) {
|
&& returnType != void.class) {
|
||||||
// public Point pointFromJson(JsonReader jsonReader) throws Exception {
|
// public Point pointFromJson(JsonReader jsonReader) throws Exception {
|
||||||
return new FromAdapter(returnType, adapter, method) {
|
Set<? extends Annotation> returnTypeAnnotations = Util.jsonAnnotations(method);
|
||||||
|
return new AdapterMethod(returnType, returnTypeAnnotations, adapter, method) {
|
||||||
@Override public Object fromJson(Moshi moshi, JsonReader reader)
|
@Override public Object fromJson(Moshi moshi, JsonReader reader)
|
||||||
throws IOException, IllegalAccessException, InvocationTargetException {
|
throws IOException, IllegalAccessException, InvocationTargetException {
|
||||||
return method.invoke(adapter, reader);
|
return method.invoke(adapter, reader);
|
||||||
@@ -188,10 +184,13 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
|
|
||||||
} else if (parameterTypes.length == 1 && returnType != void.class) {
|
} else if (parameterTypes.length == 1 && returnType != void.class) {
|
||||||
// public Point pointFromJson(List<Integer> o) throws Exception {
|
// public Point pointFromJson(List<Integer> o) throws Exception {
|
||||||
return new FromAdapter(returnType, adapter, method) {
|
Set<? extends Annotation> returnTypeAnnotations = Util.jsonAnnotations(method);
|
||||||
|
final Set<? extends Annotation> parameterAnnotations
|
||||||
|
= Util.jsonAnnotations(method.getParameterAnnotations()[0]);
|
||||||
|
return new AdapterMethod(returnType, returnTypeAnnotations, adapter, method) {
|
||||||
@Override public Object fromJson(Moshi moshi, JsonReader reader)
|
@Override public Object fromJson(Moshi moshi, JsonReader reader)
|
||||||
throws IOException, IllegalAccessException, InvocationTargetException {
|
throws IOException, IllegalAccessException, InvocationTargetException {
|
||||||
JsonAdapter<Object> delegate = moshi.adapter(parameterTypes[0]);
|
JsonAdapter<Object> delegate = moshi.adapter(parameterTypes[0], parameterAnnotations);
|
||||||
Object intermediate = delegate.fromJson(reader);
|
Object intermediate = delegate.fromJson(reader);
|
||||||
return method.invoke(adapter, intermediate);
|
return method.invoke(adapter, intermediate);
|
||||||
}
|
}
|
||||||
@@ -205,18 +204,40 @@ final class AdapterMethodsFactory implements JsonAdapter.Factory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static abstract class FromAdapter {
|
/** Returns the matching adapter method from the list. */
|
||||||
|
private static AdapterMethod get(
|
||||||
|
List<AdapterMethod> adapterMethods, Type type, Set<? extends Annotation> annotations) {
|
||||||
|
for (int i = 0, size = adapterMethods.size(); i < size; i++) {
|
||||||
|
AdapterMethod adapterMethod = adapterMethods.get(i);
|
||||||
|
if (adapterMethod.type.equals(type) && adapterMethod.annotations.equals(annotations)) {
|
||||||
|
return adapterMethod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class AdapterMethod {
|
||||||
final Type type;
|
final Type type;
|
||||||
|
final Set<? extends Annotation> annotations;
|
||||||
final Object adapter;
|
final Object adapter;
|
||||||
final Method method;
|
final Method method;
|
||||||
|
|
||||||
public FromAdapter(Type type, Object adapter, Method method) {
|
public AdapterMethod(Type type,
|
||||||
|
Set<? extends Annotation> annotations, Object adapter, Method method) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.annotations = annotations;
|
||||||
this.adapter = adapter;
|
this.adapter = adapter;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Object fromJson(Moshi moshi, JsonReader reader)
|
public void toJson(Moshi moshi, JsonWriter writer, Object value)
|
||||||
throws IOException, IllegalAccessException, InvocationTargetException;
|
throws IOException, IllegalAccessException, InvocationTargetException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object fromJson(Moshi moshi, JsonReader reader)
|
||||||
|
throws IOException, IllegalAccessException, InvocationTargetException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,11 +16,12 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts arrays to JSON arrays containing their converted contents. This
|
* Converts arrays to JSON arrays containing their converted contents. This
|
||||||
@@ -28,9 +29,11 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
final class ArrayJsonAdapter extends JsonAdapter<Object> {
|
final class ArrayJsonAdapter extends JsonAdapter<Object> {
|
||||||
public static final Factory FACTORY = new Factory() {
|
public static final Factory FACTORY = new Factory() {
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
Type elementType = Types.arrayComponentType(type);
|
Type elementType = Types.arrayComponentType(type);
|
||||||
if (elementType == null) return null;
|
if (elementType == null) return null;
|
||||||
|
if (!annotations.isEmpty()) return null;
|
||||||
Class<?> elementClass = Types.getRawType(elementType);
|
Class<?> elementClass = Types.getRawType(elementType);
|
||||||
JsonAdapter<Object> elementAdapter = moshi.adapter(elementType);
|
JsonAdapter<Object> elementAdapter = moshi.adapter(elementType);
|
||||||
return new ArrayJsonAdapter(elementClass, elementAdapter).nullSafe();
|
return new ArrayJsonAdapter(elementClass, elementAdapter).nullSafe();
|
||||||
|
@@ -16,12 +16,13 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,9 +32,11 @@ import java.util.TreeMap;
|
|||||||
*/
|
*/
|
||||||
final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
||||||
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() {
|
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() {
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
Class<?> rawType = Types.getRawType(type);
|
Class<?> rawType = Types.getRawType(type);
|
||||||
if (rawType.isInterface() || rawType.isEnum() || isPlatformType(rawType)) return null;
|
if (rawType.isInterface() || rawType.isEnum() || isPlatformType(rawType)) return null;
|
||||||
|
if (!annotations.isEmpty()) return null;
|
||||||
|
|
||||||
if (rawType.getEnclosingClass() != null && !Modifier.isStatic(rawType.getModifiers())) {
|
if (rawType.getEnclosingClass() != null && !Modifier.isStatic(rawType.getModifiers())) {
|
||||||
if (rawType.getSimpleName().isEmpty()) {
|
if (rawType.getSimpleName().isEmpty()) {
|
||||||
@@ -66,7 +69,8 @@ final class ClassJsonAdapter<T> extends JsonAdapter<T> {
|
|||||||
|
|
||||||
// Look up a type adapter for this type.
|
// Look up a type adapter for this type.
|
||||||
Type fieldType = Types.resolve(type, rawType, field.getGenericType());
|
Type fieldType = Types.resolve(type, rawType, field.getGenericType());
|
||||||
JsonAdapter<Object> adapter = moshi.adapter(fieldType, field);
|
Set<? extends Annotation> annotations = Util.jsonAnnotations(field);
|
||||||
|
JsonAdapter<Object> adapter = moshi.adapter(fieldType, annotations);
|
||||||
|
|
||||||
// Create the binding between field and JSON.
|
// Create the binding between field and JSON.
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
|
@@ -16,7 +16,7 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -27,8 +27,10 @@ import java.util.Set;
|
|||||||
/** Converts collection types to JSON arrays containing their converted contents. */
|
/** Converts collection types to JSON arrays containing their converted contents. */
|
||||||
abstract class CollectionJsonAdapter<C extends Collection<T>, T> extends JsonAdapter<C> {
|
abstract class CollectionJsonAdapter<C extends Collection<T>, T> extends JsonAdapter<C> {
|
||||||
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() {
|
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() {
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
Class<?> rawType = Types.getRawType(type);
|
Class<?> rawType = Types.getRawType(type);
|
||||||
|
if (!annotations.isEmpty()) return null;
|
||||||
if (rawType == List.class || rawType == Collection.class) {
|
if (rawType == List.class || rawType == Collection.class) {
|
||||||
return newArrayListAdapter(type, moshi).nullSafe();
|
return newArrayListAdapter(type, moshi).nullSafe();
|
||||||
} else if (rawType == Set.class) {
|
} else if (rawType == Set.class) {
|
||||||
|
@@ -16,8 +16,9 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Set;
|
||||||
import okio.Buffer;
|
import okio.Buffer;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import okio.BufferedSource;
|
import okio.BufferedSource;
|
||||||
@@ -107,6 +108,6 @@ public abstract class JsonAdapter<T> {
|
|||||||
* <p>Implementations may use to {@link Moshi#adapter} to compose adapters of other types, or
|
* <p>Implementations may use to {@link Moshi#adapter} to compose adapters of other types, or
|
||||||
* {@link Moshi#nextAdapter} to delegate to the underlying adapter of the same type.
|
* {@link Moshi#nextAdapter} to delegate to the underlying adapter of the same type.
|
||||||
*/
|
*/
|
||||||
JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi);
|
JsonAdapter<?> create(Type type, Set<? extends Annotation> annotations, Moshi moshi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,9 @@ package com.squareup.moshi;
|
|||||||
|
|
||||||
/** Thrown when a JSON document doesn't match the expected format. */
|
/** Thrown when a JSON document doesn't match the expected format. */
|
||||||
public final class JsonDataException extends RuntimeException {
|
public final class JsonDataException extends RuntimeException {
|
||||||
|
public JsonDataException() {
|
||||||
|
}
|
||||||
|
|
||||||
public JsonDataException(String message) {
|
public JsonDataException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
30
moshi/src/main/java/com/squareup/moshi/JsonQualifier.java
Normal file
30
moshi/src/main/java/com/squareup/moshi/JsonQualifier.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Square, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.squareup.moshi;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
/** Annotates another annotation, causing it to specialize how values are encoded and decoded. */
|
||||||
|
@Target(ANNOTATION_TYPE)
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface JsonQualifier {
|
||||||
|
}
|
@@ -16,9 +16,10 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts maps with string keys to JSON objects.
|
* Converts maps with string keys to JSON objects.
|
||||||
@@ -27,7 +28,9 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
final class MapJsonAdapter<K, V> extends JsonAdapter<Map<K, V>> {
|
final class MapJsonAdapter<K, V> extends JsonAdapter<Map<K, V>> {
|
||||||
public static final Factory FACTORY = new Factory() {
|
public static final Factory FACTORY = new Factory() {
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
|
if (!annotations.isEmpty()) return null;
|
||||||
Class<?> rawType = Types.getRawType(type);
|
Class<?> rawType = Types.getRawType(type);
|
||||||
if (rawType != Map.class) return null;
|
if (rawType != Map.class) return null;
|
||||||
Type[] keyAndValue = Types.mapKeyAndValueTypes(type, rawType);
|
Type[] keyAndValue = Types.mapKeyAndValueTypes(type, rawType);
|
||||||
|
@@ -17,11 +17,11 @@ package com.squareup.moshi;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Coordinates binding between JSON values and Java objects.
|
* Coordinates binding between JSON values and Java objects.
|
||||||
@@ -51,19 +51,22 @@ public final class Moshi {
|
|||||||
return adapter(type, Util.NO_ANNOTATIONS);
|
return adapter(type, Util.NO_ANNOTATIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> JsonAdapter<T> adapter(Type type, AnnotatedElement annotations) {
|
public <T> JsonAdapter<T> adapter(Type type, Set<? extends Annotation> annotations) {
|
||||||
// TODO: support re-entrant calls.
|
|
||||||
return createAdapter(0, type, annotations);
|
return createAdapter(0, type, annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> JsonAdapter<T> nextAdapter(JsonAdapter.Factory skipPast, Type type,
|
public <T> JsonAdapter<T> nextAdapter(JsonAdapter.Factory skipPast, Type type,
|
||||||
AnnotatedElement annotations) {
|
Set<? extends Annotation> annotations) {
|
||||||
return createAdapter(factories.indexOf(skipPast) + 1, type, annotations);
|
return createAdapter(factories.indexOf(skipPast) + 1, type, annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> JsonAdapter<T> nextAdapter(JsonAdapter.Factory skipPast, Type type) {
|
||||||
|
return nextAdapter(skipPast, type, Util.NO_ANNOTATIONS);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") // Factories are required to return only matching JsonAdapters.
|
@SuppressWarnings("unchecked") // Factories are required to return only matching JsonAdapters.
|
||||||
private <T> JsonAdapter<T> createAdapter(
|
private <T> JsonAdapter<T> createAdapter(
|
||||||
int firstIndex, Type type, AnnotatedElement annotations) {
|
int firstIndex, Type type, Set<? extends Annotation> annotations) {
|
||||||
List<DeferredAdapter<?>> deferredAdapters = reentrantCalls.get();
|
List<DeferredAdapter<?>> deferredAdapters = reentrantCalls.get();
|
||||||
if (deferredAdapters == null) {
|
if (deferredAdapters == null) {
|
||||||
deferredAdapters = new ArrayList<>();
|
deferredAdapters = new ArrayList<>();
|
||||||
@@ -91,7 +94,7 @@ public final class Moshi {
|
|||||||
deferredAdapters.remove(deferredAdapters.size() - 1);
|
deferredAdapters.remove(deferredAdapters.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("no JsonAdapter for " + type);
|
throw new IllegalArgumentException("no JsonAdapter for " + type + " annotated " + annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
@@ -103,8 +106,8 @@ public final class Moshi {
|
|||||||
|
|
||||||
return add(new JsonAdapter.Factory() {
|
return add(new JsonAdapter.Factory() {
|
||||||
@Override public JsonAdapter<?> create(
|
@Override public JsonAdapter<?> create(
|
||||||
Type targetType, AnnotatedElement annotations, Moshi moshi) {
|
Type targetType, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
return Util.typesMatch(type, targetType) ? jsonAdapter : null;
|
return annotations.isEmpty() && Util.typesMatch(type, targetType) ? jsonAdapter : null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -114,13 +117,16 @@ public final class Moshi {
|
|||||||
if (type == null) throw new IllegalArgumentException("type == null");
|
if (type == null) throw new IllegalArgumentException("type == null");
|
||||||
if (annotation == null) throw new IllegalArgumentException("annotation == null");
|
if (annotation == null) throw new IllegalArgumentException("annotation == null");
|
||||||
if (jsonAdapter == null) throw new IllegalArgumentException("jsonAdapter == null");
|
if (jsonAdapter == null) throw new IllegalArgumentException("jsonAdapter == null");
|
||||||
|
if (!annotation.isAnnotationPresent(JsonQualifier.class)) {
|
||||||
|
throw new IllegalArgumentException(annotation + " does not have @JsonQualifier");
|
||||||
|
}
|
||||||
|
|
||||||
return add(new JsonAdapter.Factory() {
|
return add(new JsonAdapter.Factory() {
|
||||||
@Override public JsonAdapter<?> create(
|
@Override public JsonAdapter<?> create(
|
||||||
Type targetType, AnnotatedElement annotations, Moshi moshi) {
|
Type targetType, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
return Util.typesMatch(type, targetType) && annotations.isAnnotationPresent(annotation)
|
if (!Util.typesMatch(type, targetType)) return null;
|
||||||
? jsonAdapter
|
if (!Util.isAnnotationPresent(annotations, annotation)) return null;
|
||||||
: null;
|
return jsonAdapter;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -150,10 +156,10 @@ public final class Moshi {
|
|||||||
*/
|
*/
|
||||||
private static class DeferredAdapter<T> extends JsonAdapter<T> {
|
private static class DeferredAdapter<T> extends JsonAdapter<T> {
|
||||||
private Type type;
|
private Type type;
|
||||||
private AnnotatedElement annotations;
|
private Set<? extends Annotation> annotations;
|
||||||
private JsonAdapter<T> delegate;
|
private JsonAdapter<T> delegate;
|
||||||
|
|
||||||
public DeferredAdapter(Type type, AnnotatedElement annotations) {
|
public DeferredAdapter(Type type, Set<? extends Annotation> annotations) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.annotations = annotations;
|
this.annotations = annotations;
|
||||||
}
|
}
|
||||||
|
@@ -16,13 +16,16 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
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.Set;
|
||||||
|
|
||||||
final class StandardJsonAdapters {
|
final class StandardJsonAdapters {
|
||||||
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() {
|
public static final JsonAdapter.Factory FACTORY = new JsonAdapter.Factory() {
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
|
if (!annotations.isEmpty()) return null;
|
||||||
if (type == boolean.class) return BOOLEAN_JSON_ADAPTER;
|
if (type == boolean.class) return BOOLEAN_JSON_ADAPTER;
|
||||||
if (type == byte.class) return BYTE_JSON_ADAPTER;
|
if (type == byte.class) return BYTE_JSON_ADAPTER;
|
||||||
if (type == char.class) return CHARACTER_JSON_ADAPTER;
|
if (type == char.class) return CHARACTER_JSON_ADAPTER;
|
||||||
|
@@ -18,27 +18,39 @@ package com.squareup.moshi;
|
|||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
final class Util {
|
final class Util {
|
||||||
public static final Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0];
|
public static final Set<Annotation> NO_ANNOTATIONS = Collections.emptySet();
|
||||||
|
|
||||||
public static final AnnotatedElement NO_ANNOTATIONS = new AnnotatedElement() {
|
|
||||||
@Override public boolean isAnnotationPresent(Class<? extends Annotation> aClass) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
@Override public <T extends Annotation> T getAnnotation(Class<T> tClass) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
@Override public Annotation[] getAnnotations() {
|
|
||||||
return EMPTY_ANNOTATIONS_ARRAY;
|
|
||||||
}
|
|
||||||
@Override public Annotation[] getDeclaredAnnotations() {
|
|
||||||
return EMPTY_ANNOTATIONS_ARRAY;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static boolean typesMatch(Type pattern, Type candidate) {
|
public static boolean typesMatch(Type pattern, Type candidate) {
|
||||||
// TODO: permit raw types (like Set.class) to match non-raw candidates (like Set<Long>).
|
// TODO: permit raw types (like Set.class) to match non-raw candidates (like Set<Long>).
|
||||||
return pattern.equals(candidate);
|
return pattern.equals(candidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Set<? extends Annotation> jsonAnnotations(AnnotatedElement annotatedElement) {
|
||||||
|
return jsonAnnotations(annotatedElement.getAnnotations());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set<? extends Annotation> jsonAnnotations(Annotation[] annotations) {
|
||||||
|
Set<Annotation> result = null;
|
||||||
|
for (Annotation annotation : annotations) {
|
||||||
|
if (annotation.annotationType().isAnnotationPresent(JsonQualifier.class)) {
|
||||||
|
if (result == null) result = new LinkedHashSet<>();
|
||||||
|
result.add(annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result != null ? Collections.unmodifiableSet(result) : Util.NO_ANNOTATIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAnnotationPresent(
|
||||||
|
Set<? extends Annotation> annotations, Class<? extends Annotation> annotationClass) {
|
||||||
|
if (annotations.isEmpty()) return false; // Save an iterator in the common case.
|
||||||
|
for (Annotation annotation : annotations) {
|
||||||
|
if (annotation.annotationType() == annotationClass) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,9 +16,10 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.Set;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
@@ -63,10 +64,12 @@ public final class CircularAdaptersTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@JsonQualifier
|
||||||
public @interface Left {
|
public @interface Left {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@JsonQualifier
|
||||||
public @interface Right {
|
public @interface Right {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,19 +100,20 @@ public final class CircularAdaptersTest {
|
|||||||
* work.
|
* work.
|
||||||
*/
|
*/
|
||||||
static class PrefixingNodeFactory implements JsonAdapter.Factory {
|
static class PrefixingNodeFactory implements JsonAdapter.Factory {
|
||||||
@Override public JsonAdapter<?> create(Type type, AnnotatedElement annotations, Moshi moshi) {
|
@Override public JsonAdapter<?> create(
|
||||||
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
if (type != Node.class) return null;
|
if (type != Node.class) return null;
|
||||||
|
|
||||||
final String prefix;
|
final String prefix;
|
||||||
if (annotations.isAnnotationPresent(Left.class)) {
|
if (Util.isAnnotationPresent(annotations, Left.class)) {
|
||||||
prefix = "L ";
|
prefix = "L ";
|
||||||
} else if (annotations.isAnnotationPresent(Right.class)) {
|
} else if (Util.isAnnotationPresent(annotations, Right.class)) {
|
||||||
prefix = "R ";
|
prefix = "R ";
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final JsonAdapter<Node> delegate = moshi.nextAdapter(this, Node.class, annotations);
|
final JsonAdapter<Node> delegate = moshi.nextAdapter(this, Node.class);
|
||||||
|
|
||||||
return new JsonAdapter<Node>() {
|
return new JsonAdapter<Node>() {
|
||||||
@Override public void toJson(JsonWriter writer, Node value) throws IOException {
|
@Override public void toJson(JsonWriter writer, Node value) throws IOException {
|
||||||
|
@@ -391,7 +391,7 @@ public final class ClassJsonAdapterTest {
|
|||||||
|
|
||||||
private <T> String toJson(Class<T> type, T value) throws IOException {
|
private <T> String toJson(Class<T> type, T value) throws IOException {
|
||||||
@SuppressWarnings("unchecked") // Factory.create returns an adapter that matches its argument.
|
@SuppressWarnings("unchecked") // Factory.create returns an adapter that matches its argument.
|
||||||
JsonAdapter<T> jsonAdapter = (JsonAdapter<T>) ClassJsonAdapter.FACTORY.create(
|
JsonAdapter<T> jsonAdapter = (JsonAdapter<T>) ClassJsonAdapter.FACTORY.create(
|
||||||
type, NO_ANNOTATIONS, moshi);
|
type, NO_ANNOTATIONS, moshi);
|
||||||
|
|
||||||
// Wrap in an array to avoid top-level object warnings without going completely lenient.
|
// Wrap in an array to avoid top-level object warnings without going completely lenient.
|
||||||
@@ -409,7 +409,7 @@ public final class ClassJsonAdapterTest {
|
|||||||
|
|
||||||
private <T> T fromJson(Class<T> type, String json) throws IOException {
|
private <T> T fromJson(Class<T> type, String json) throws IOException {
|
||||||
@SuppressWarnings("unchecked") // Factory.create returns an adapter that matches its argument.
|
@SuppressWarnings("unchecked") // Factory.create returns an adapter that matches its argument.
|
||||||
JsonAdapter<T> jsonAdapter = (JsonAdapter<T>) ClassJsonAdapter.FACTORY.create(
|
JsonAdapter<T> jsonAdapter = (JsonAdapter<T>) ClassJsonAdapter.FACTORY.create(
|
||||||
type, NO_ANNOTATIONS, moshi);
|
type, NO_ANNOTATIONS, moshi);
|
||||||
// Wrap in an array to avoid top-level object warnings without going completely lenient.
|
// Wrap in an array to avoid top-level object warnings without going completely lenient.
|
||||||
JsonReader jsonReader = newReader("[" + json + "]");
|
JsonReader jsonReader = newReader("[" + json + "]");
|
||||||
|
367
moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java
Normal file
367
moshi/src/test/java/com/squareup/moshi/JsonQualifiersTest.java
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Square, Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.squareup.moshi;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.util.Date;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
public final class JsonQualifiersTest {
|
||||||
|
@Test public void builtInTypes() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new BuiltInTypesJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooString> adapter = moshi.adapter(StringAndFooString.class);
|
||||||
|
|
||||||
|
StringAndFooString v1 = new StringAndFooString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobar\"}");
|
||||||
|
|
||||||
|
StringAndFooString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobar\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BuiltInTypesJsonAdapter {
|
||||||
|
@ToJson String fooPrefixStringToString(@FooPrefix String s) {
|
||||||
|
return "foo" + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson @FooPrefix String fooPrefixStringFromString(String s) throws Exception {
|
||||||
|
if (!s.startsWith("foo")) throw new JsonDataException();
|
||||||
|
return s.substring(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void readerWriterJsonAdapter() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new ReaderWriterJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooString> adapter = moshi.adapter(StringAndFooString.class);
|
||||||
|
|
||||||
|
StringAndFooString v1 = new StringAndFooString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobar\"}");
|
||||||
|
|
||||||
|
StringAndFooString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobar\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ReaderWriterJsonAdapter {
|
||||||
|
@ToJson void fooPrefixStringToString(JsonWriter jsonWriter, @FooPrefix String s)
|
||||||
|
throws IOException {
|
||||||
|
jsonWriter.value("foo" + s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson @FooPrefix String fooPrefixStringFromString(JsonReader reader) throws Exception {
|
||||||
|
String s = reader.nextString();
|
||||||
|
if (!s.startsWith("foo")) throw new JsonDataException();
|
||||||
|
return s.substring(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fields with this annotation get "foo" as a prefix in the JSON. */
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@JsonQualifier
|
||||||
|
public @interface FooPrefix {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fields with this annotation get "baz" as a suffix in the JSON. */
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@JsonQualifier
|
||||||
|
public @interface BazSuffix {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringAndFooString {
|
||||||
|
String a;
|
||||||
|
@FooPrefix String b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class StringAndFooBazString {
|
||||||
|
String a;
|
||||||
|
@FooPrefix @BazSuffix String b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void builtInTypesWithMultipleAnnotations() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new BuiltInTypesWithMultipleAnnotationsJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooBazString> adapter = moshi.adapter(StringAndFooBazString.class);
|
||||||
|
|
||||||
|
StringAndFooBazString v1 = new StringAndFooBazString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
|
||||||
|
StringAndFooBazString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BuiltInTypesWithMultipleAnnotationsJsonAdapter {
|
||||||
|
@ToJson String fooPrefixAndBazSuffixStringToString(@FooPrefix @BazSuffix String s) {
|
||||||
|
return "foo" + s + "baz";
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson @FooPrefix @BazSuffix String fooPrefixAndBazSuffixStringFromString(
|
||||||
|
String s) throws Exception {
|
||||||
|
if (!s.startsWith("foo")) throw new JsonDataException();
|
||||||
|
if (!s.endsWith("baz")) throw new JsonDataException();
|
||||||
|
return s.substring(3, s.length() - 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void readerWriterWithMultipleAnnotations() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new ReaderWriterWithMultipleAnnotationsJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooBazString> adapter = moshi.adapter(StringAndFooBazString.class);
|
||||||
|
|
||||||
|
StringAndFooBazString v1 = new StringAndFooBazString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
|
||||||
|
StringAndFooBazString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ReaderWriterWithMultipleAnnotationsJsonAdapter {
|
||||||
|
@ToJson void fooPrefixAndBazSuffixStringToString(
|
||||||
|
JsonWriter jsonWriter, @FooPrefix @BazSuffix String s) throws IOException {
|
||||||
|
jsonWriter.value("foo" + s + "baz");
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson @FooPrefix @BazSuffix String fooPrefixAndBazSuffixStringFromString(
|
||||||
|
JsonReader reader) throws Exception {
|
||||||
|
String s = reader.nextString();
|
||||||
|
if (!s.startsWith("foo")) throw new JsonDataException();
|
||||||
|
if (!s.endsWith("baz")) throw new JsonDataException();
|
||||||
|
return s.substring(3, s.length() - 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void basicTypesAnnotationDelegating() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new BuiltInTypesDelegatingJsonAdapter())
|
||||||
|
.add(new BuiltInTypesJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooBazString> adapter = moshi.adapter(StringAndFooBazString.class);
|
||||||
|
|
||||||
|
StringAndFooBazString v1 = new StringAndFooBazString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
|
||||||
|
StringAndFooBazString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BuiltInTypesDelegatingJsonAdapter {
|
||||||
|
@ToJson @FooPrefix String fooPrefixAndBazSuffixStringToString(@FooPrefix @BazSuffix String s) {
|
||||||
|
return s + "baz";
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson @FooPrefix @BazSuffix String fooPrefixAndBazSuffixStringFromString(
|
||||||
|
@FooPrefix String s) throws Exception {
|
||||||
|
if (!s.endsWith("baz")) throw new JsonDataException();
|
||||||
|
return s.substring(0, s.length() - 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void readerWriterAnnotationDelegating() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new BuiltInTypesDelegatingJsonAdapter())
|
||||||
|
.add(new ReaderWriterJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooBazString> adapter = moshi.adapter(StringAndFooBazString.class);
|
||||||
|
|
||||||
|
StringAndFooBazString v1 = new StringAndFooBazString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
|
||||||
|
StringAndFooBazString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobarbaz\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void manualJsonAdapter() throws Exception {
|
||||||
|
JsonAdapter<String> fooPrefixAdapter = new JsonAdapter<String>() {
|
||||||
|
@Override public String fromJson(JsonReader reader) throws IOException {
|
||||||
|
String s = reader.nextString();
|
||||||
|
if (!s.startsWith("foo")) throw new JsonDataException();
|
||||||
|
return s.substring(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void toJson(JsonWriter writer, String value) throws IOException {
|
||||||
|
writer.value("foo" + value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(String.class, FooPrefix.class, fooPrefixAdapter)
|
||||||
|
.build();
|
||||||
|
JsonAdapter<StringAndFooString> adapter = moshi.adapter(StringAndFooString.class);
|
||||||
|
|
||||||
|
StringAndFooString v1 = new StringAndFooString();
|
||||||
|
v1.a = "aa";
|
||||||
|
v1.b = "bar";
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":\"aa\",\"b\":\"foobar\"}");
|
||||||
|
|
||||||
|
StringAndFooString v2 = adapter.fromJson("{\"a\":\"aa\",\"b\":\"foobar\"}");
|
||||||
|
assertThat(v2.a).isEqualTo("aa");
|
||||||
|
assertThat(v2.b).isEqualTo("bar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void noJsonAdapterForAnnotatedType() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder().build();
|
||||||
|
try {
|
||||||
|
moshi.adapter(StringAndFooString.class);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void annotationWithoutJsonQualifierIsIgnoredByAdapterMethods() throws Exception {
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new MissingJsonQualifierJsonAdapter())
|
||||||
|
.build();
|
||||||
|
JsonAdapter<DateAndMillisDate> adapter = moshi.adapter(DateAndMillisDate.class);
|
||||||
|
|
||||||
|
DateAndMillisDate v1 = new DateAndMillisDate();
|
||||||
|
v1.a = new Date(5);
|
||||||
|
v1.b = new Date(7);
|
||||||
|
assertThat(adapter.toJson(v1)).isEqualTo("{\"a\":5,\"b\":7}");
|
||||||
|
|
||||||
|
DateAndMillisDate v2 = adapter.fromJson("{\"a\":5,\"b\":7}");
|
||||||
|
assertThat(v2.a).isEqualTo(new Date(5));
|
||||||
|
assertThat(v2.b).isEqualTo(new Date(7));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Despite the fact that these methods are annotated, they match all dates. */
|
||||||
|
static class MissingJsonQualifierJsonAdapter {
|
||||||
|
@ToJson long dateToJson(@Millis Date d) {
|
||||||
|
return d.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
@FromJson @Millis Date jsonToDate(long value) throws Exception {
|
||||||
|
return new Date(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This annotation does nothing. */
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface Millis {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DateAndMillisDate {
|
||||||
|
Date a;
|
||||||
|
@Millis Date b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void annotationWithoutJsonQualifierIsRejectedOnRegistration() throws Exception {
|
||||||
|
JsonAdapter<Date> jsonAdapter = new JsonAdapter<Date>() {
|
||||||
|
@Override public Date fromJson(JsonReader reader) throws IOException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void toJson(JsonWriter writer, Date value) throws IOException {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
new Moshi.Builder().add(Date.class, Millis.class, jsonAdapter);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertThat(expected).hasMessage("interface com.squareup.moshi.JsonQualifiersTest$Millis "
|
||||||
|
+ "does not have @JsonQualifier");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void annotationsConflict() throws Exception {
|
||||||
|
try {
|
||||||
|
new Moshi.Builder().add(new AnnotationsConflictJsonAdapter());
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertThat(expected).hasMessageContaining("Conflicting @ToJson methods");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class AnnotationsConflictJsonAdapter {
|
||||||
|
@ToJson String fooPrefixStringToString(@FooPrefix String s) {
|
||||||
|
return "foo" + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToJson String fooPrefixStringToString2(@FooPrefix String s) {
|
||||||
|
return "foo" + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void toButNoFromJson() throws Exception {
|
||||||
|
// Building it is okay.
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new ToButNoFromJsonAdapter())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
moshi.adapter(StringAndFooString.class);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertThat(expected).hasMessage("no JsonAdapter for class java.lang.String "
|
||||||
|
+ "annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ToButNoFromJsonAdapter {
|
||||||
|
@ToJson String fooPrefixStringToString(@FooPrefix String s) {
|
||||||
|
return "foo" + s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test public void fromButNoToJson() throws Exception {
|
||||||
|
// Building it is okay.
|
||||||
|
Moshi moshi = new Moshi.Builder()
|
||||||
|
.add(new FromButNoToJsonAdapter())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try {
|
||||||
|
moshi.adapter(StringAndFooString.class);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertThat(expected).hasMessage("no JsonAdapter for class java.lang.String "
|
||||||
|
+ "annotated [@com.squareup.moshi.JsonQualifiersTest$FooPrefix()]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FromButNoToJsonAdapter {
|
||||||
|
@FromJson @FooPrefix String fooPrefixStringFromString(String s) throws Exception {
|
||||||
|
if (!s.startsWith("foo")) throw new JsonDataException();
|
||||||
|
return s.substring(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,8 +16,8 @@
|
|||||||
package com.squareup.moshi;
|
package com.squareup.moshi;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.reflect.AnnotatedElement;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
@@ -32,6 +32,7 @@ import org.junit.Test;
|
|||||||
import static com.squareup.moshi.TestUtil.newReader;
|
import static com.squareup.moshi.TestUtil.newReader;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public final class MoshiTest {
|
public final class MoshiTest {
|
||||||
@@ -591,7 +592,8 @@ public final class MoshiTest {
|
|||||||
.add(new UppercaseAdapterFactory())
|
.add(new UppercaseAdapterFactory())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
AnnotatedElement annotations = MoshiTest.class.getDeclaredField("uppercaseString");
|
Field uppercaseString = MoshiTest.class.getDeclaredField("uppercaseString");
|
||||||
|
Set<? extends Annotation> annotations = Util.jsonAnnotations(uppercaseString);
|
||||||
JsonAdapter<String> adapter = moshi.<String>adapter(String.class, annotations).lenient();
|
JsonAdapter<String> adapter = moshi.<String>adapter(String.class, annotations).lenient();
|
||||||
assertThat(adapter.toJson("a")).isEqualTo("\"A\"");
|
assertThat(adapter.toJson("a")).isEqualTo("\"A\"");
|
||||||
assertThat(adapter.fromJson("\"b\"")).isEqualTo("B");
|
assertThat(adapter.fromJson("\"b\"")).isEqualTo("B");
|
||||||
@@ -638,10 +640,14 @@ public final class MoshiTest {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
Field uppercaseStringsField = MoshiTest.class.getDeclaredField("uppercaseStrings");
|
Field uppercaseStringsField = MoshiTest.class.getDeclaredField("uppercaseStrings");
|
||||||
JsonAdapter<List<String>> adapter = moshi.adapter(uppercaseStringsField.getGenericType(),
|
try {
|
||||||
uppercaseStringsField);
|
moshi.adapter(uppercaseStringsField.getGenericType(),
|
||||||
assertThat(adapter.toJson(Arrays.asList("a"))).isEqualTo("[\"a\"]");
|
Util.jsonAnnotations(uppercaseStringsField));
|
||||||
assertThat(adapter.fromJson("[\"b\"]")).isEqualTo(Arrays.asList("b"));
|
fail();
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals("no JsonAdapter for java.util.List<java.lang.String> annotated "
|
||||||
|
+ "[@com.squareup.moshi.MoshiTest$Uppercase()]", expected.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void objectArray() throws Exception {
|
@Test public void objectArray() throws Exception {
|
||||||
@@ -753,9 +759,8 @@ public final class MoshiTest {
|
|||||||
|
|
||||||
static class MealDealAdapterFactory implements JsonAdapter.Factory {
|
static class MealDealAdapterFactory implements JsonAdapter.Factory {
|
||||||
@Override public JsonAdapter<?> create(
|
@Override public JsonAdapter<?> create(
|
||||||
Type type, AnnotatedElement annotations, Moshi moshi) {
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
if (!type.equals(MealDeal.class)) return null;
|
if (!type.equals(MealDeal.class)) return null;
|
||||||
|
|
||||||
final JsonAdapter<Pizza> pizzaAdapter = moshi.adapter(Pizza.class);
|
final JsonAdapter<Pizza> pizzaAdapter = moshi.adapter(Pizza.class);
|
||||||
final JsonAdapter<String> drinkAdapter = moshi.adapter(String.class);
|
final JsonAdapter<String> drinkAdapter = moshi.adapter(String.class);
|
||||||
return new JsonAdapter<MealDeal>() {
|
return new JsonAdapter<MealDeal>() {
|
||||||
@@ -778,16 +783,17 @@ public final class MoshiTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Retention(RUNTIME)
|
@Retention(RUNTIME)
|
||||||
|
@JsonQualifier
|
||||||
public @interface Uppercase {
|
public @interface Uppercase {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class UppercaseAdapterFactory implements JsonAdapter.Factory {
|
static class UppercaseAdapterFactory implements JsonAdapter.Factory {
|
||||||
@Override public JsonAdapter<?> create(
|
@Override public JsonAdapter<?> create(
|
||||||
Type type, AnnotatedElement annotations, Moshi moshi) {
|
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
|
||||||
if (!type.equals(String.class)) return null;
|
if (!type.equals(String.class)) return null;
|
||||||
if (!annotations.isAnnotationPresent(Uppercase.class)) return null;
|
if (!Util.isAnnotationPresent(annotations, Uppercase.class)) return null;
|
||||||
|
|
||||||
final JsonAdapter<String> stringAdapter = moshi.nextAdapter(this, String.class, annotations);
|
final JsonAdapter<String> stringAdapter = moshi.nextAdapter(this, String.class);
|
||||||
return new JsonAdapter<String>() {
|
return new JsonAdapter<String>() {
|
||||||
@Override public String fromJson(JsonReader reader) throws IOException {
|
@Override public String fromJson(JsonReader reader) throws IOException {
|
||||||
String s = stringAdapter.fromJson(reader);
|
String s = stringAdapter.fromJson(reader);
|
||||||
|
Reference in New Issue
Block a user