Added support for JsonAdapter annotation on fields

This commit is contained in:
Inderjeet Singh 2014-03-09 07:28:04 +00:00
parent 67d512ee7d
commit bf549f0589
4 changed files with 34 additions and 15 deletions

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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()) {

View File

@ -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;
}