Added support for JsonAdapter annotation on fields
This commit is contained in:
parent
67d512ee7d
commit
bf549f0589
@ -72,7 +72,7 @@ import com.google.gson.TypeAdapter;
|
||||
*/
|
||||
// Note that the above example is taken from JsonAdapterANnotationTest.
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
public @interface JsonAdapter {
|
||||
|
||||
Class<? extends TypeAdapter<?>> value();
|
||||
|
@ -43,9 +43,15 @@ public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapte
|
||||
Class<? super T> clazz = targetType.getRawType();
|
||||
JsonAdapter annotation = clazz.getAnnotation(JsonAdapter.class);
|
||||
if (annotation == null) return null;
|
||||
Class<? extends TypeAdapter<?>> adapterClass = annotation.value();
|
||||
ObjectConstructor<? extends TypeAdapter<?>> constructor = constructorConstructor.get(TypeToken.get(adapterClass));
|
||||
TypeAdapter adapter = constructor.construct();
|
||||
TypeAdapter adapter = getAnnotationTypeAdapter(constructorConstructor, annotation);
|
||||
return adapter;
|
||||
}
|
||||
|
||||
static TypeAdapter<?> getAnnotationTypeAdapter(
|
||||
ConstructorConstructor constructorConstructor, JsonAdapter annotation) {
|
||||
Class<? extends TypeAdapter<?>> adapterClass = annotation.value();
|
||||
ObjectConstructor<? extends TypeAdapter<?>> constructor =
|
||||
constructorConstructor.get(TypeToken.get(adapterClass));
|
||||
return constructor.construct();
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,18 @@
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.FieldNamingStrategy;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.annotations.JsonAdapter;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
@ -31,11 +38,6 @@ 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;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Type adapter that reflects over the fields and methods of a class.
|
||||
@ -76,10 +78,9 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
|
||||
final Gson context, final Field field, final String name,
|
||||
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
|
||||
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
|
||||
|
||||
// special casing primitives here saves ~5% on Android...
|
||||
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
|
||||
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
|
||||
final TypeAdapter<?> typeAdapter = getFieldAdapter(context, field, fieldType);
|
||||
@SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
|
||||
@Override void write(JsonWriter writer, Object value)
|
||||
throws IOException, IllegalAccessException {
|
||||
@ -98,6 +99,18 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
|
||||
};
|
||||
}
|
||||
|
||||
private TypeAdapter<?> getFieldAdapter(Gson context, Field field, TypeToken<?> fieldType) {
|
||||
TypeAdapter<?> adapter = context.getAdapter(fieldType);
|
||||
// check if the registered adapter is a reflective type adapter. If so, JsonAdapter
|
||||
// annotation should take precedence. Somewhat hackish, but works.
|
||||
if (adapter instanceof Adapter && field.isAnnotationPresent(JsonAdapter.class)) {
|
||||
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
|
||||
return JsonAdapterAnnotationTypeAdapterFactory.getAnnotationTypeAdapter(
|
||||
constructorConstructor, annotation);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
|
||||
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
|
||||
if (raw.isInterface()) {
|
||||
|
@ -36,9 +36,9 @@ import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Functional tests for the {@link com.google.gson.annotations.JsonAdapter} annotation.
|
||||
* Functional tests for the {@link com.google.gson.annotations.JsonAdapter} annotation on classes.
|
||||
*/
|
||||
public final class JsonAdapterAnnotationTest extends TestCase {
|
||||
public final class JsonAdapterAnnotationOnClassesTest extends TestCase {
|
||||
|
||||
public void testJsonAdapterInvoked() {
|
||||
Gson gson = new Gson();
|
||||
@ -154,8 +154,8 @@ public final class JsonAdapterAnnotationTest extends TestCase {
|
||||
// This class is used in JsonAdapter Javadoc as an example
|
||||
@JsonAdapter(UserJsonAdapter.class)
|
||||
private static class User {
|
||||
public final String firstName, lastName;
|
||||
private User(String firstName, String lastName) {
|
||||
final String firstName, lastName;
|
||||
User(String firstName, String lastName) {
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
}
|
Loading…
Reference in New Issue
Block a user