Change field annotations to take precedence over registered type adapters.
This commit is contained in:
parent
f9a302e22a
commit
125e6d9d3d
@ -49,10 +49,8 @@ import java.math.BigInteger;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the main class for using Gson. Gson is typically used by first constructing a
|
* This is the main class for using Gson. Gson is typically used by first constructing a
|
||||||
@ -115,15 +113,6 @@ public final class Gson {
|
|||||||
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache
|
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache
|
||||||
= Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>());
|
= Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>());
|
||||||
|
|
||||||
/** Indicates whether Gson is in the phase of constructor invocation. It is used to determine
|
|
||||||
* whether to add a constructor in preconfiguredGeneratedTypeAdapter set or not. */
|
|
||||||
private boolean inConstructorPhase = true;
|
|
||||||
/** List of type adapters that are generated by Gson during its constructor */
|
|
||||||
private Set<TypeAdapter<?>> preconfiguredGeneratedTypeAdapters = new HashSet<TypeAdapter<?>>();
|
|
||||||
/** List of type adapters that are generated by Gson during toJson/fromJson. */
|
|
||||||
private final ThreadLocal<Set<TypeAdapter<?>>> runtimeGeneratedTypeAdapters =
|
|
||||||
new ThreadLocal<Set<TypeAdapter<?>>>();
|
|
||||||
|
|
||||||
private final List<TypeAdapterFactory> factories;
|
private final List<TypeAdapterFactory> factories;
|
||||||
private final ConstructorConstructor constructorConstructor;
|
private final ConstructorConstructor constructorConstructor;
|
||||||
|
|
||||||
@ -254,8 +243,6 @@ public final class Gson {
|
|||||||
constructorConstructor, fieldNamingPolicy, excluder));
|
constructorConstructor, fieldNamingPolicy, excluder));
|
||||||
|
|
||||||
this.factories = Collections.unmodifiableList(factories);
|
this.factories = Collections.unmodifiableList(factories);
|
||||||
this.preconfiguredGeneratedTypeAdapters = Collections.unmodifiableSet(preconfiguredGeneratedTypeAdapters);
|
|
||||||
inConstructorPhase = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
||||||
@ -917,26 +904,4 @@ public final class Gson {
|
|||||||
.append("}")
|
.append("}")
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class $$Internal {
|
|
||||||
public static void addGeneratedTypeAdapter(Gson gson, TypeAdapter<?> typeAdapter) {
|
|
||||||
if (gson.inConstructorPhase) {
|
|
||||||
gson.preconfiguredGeneratedTypeAdapters.add(typeAdapter);
|
|
||||||
} else {
|
|
||||||
Set<TypeAdapter<?>> adapters = getRuntimeGeneratedTypeAdapters(gson);
|
|
||||||
adapters.add(typeAdapter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static boolean isGeneratedTypeAdapter(Gson gson, TypeAdapter<?> typeAdapter) {
|
|
||||||
boolean generated = gson.preconfiguredGeneratedTypeAdapters.contains(typeAdapter);
|
|
||||||
if (!generated) generated = getRuntimeGeneratedTypeAdapters(gson).contains(typeAdapter);
|
|
||||||
return generated;
|
|
||||||
}
|
|
||||||
private static Set<TypeAdapter<?>> getRuntimeGeneratedTypeAdapters(Gson gson) {
|
|
||||||
Set<TypeAdapter<?>> adapters = gson.runtimeGeneratedTypeAdapters.get();
|
|
||||||
if (adapters == null) adapters = new HashSet<TypeAdapter<?>>();
|
|
||||||
gson.runtimeGeneratedTypeAdapters.set(adapters);
|
|
||||||
return adapters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,8 @@ import java.lang.annotation.Target;
|
|||||||
import com.google.gson.TypeAdapter;
|
import com.google.gson.TypeAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An annotation that indicates the Gson {@link TypeAdapter} to use with a class or a field.
|
* An annotation that indicates the Gson {@link TypeAdapter} to use with a class
|
||||||
* Any type adapters registered in {@link com.google.gson.GsonBuilder} supersede the adapter
|
* or field.
|
||||||
* specified in this annotation.
|
|
||||||
*
|
*
|
||||||
* <p>Here is an example of how this annotation is used:</p>
|
* <p>Here is an example of how this annotation is used:</p>
|
||||||
* <pre>
|
* <pre>
|
||||||
@ -61,9 +60,6 @@ import com.google.gson.TypeAdapter;
|
|||||||
* Since User class specified UserJsonAdapter.class in @JsonAdapter annotation, it
|
* Since User class specified UserJsonAdapter.class in @JsonAdapter annotation, it
|
||||||
* will automatically be invoked to serialize/deserialize User instances. <br>
|
* will automatically be invoked to serialize/deserialize User instances. <br>
|
||||||
*
|
*
|
||||||
* If the UserJsonAdapter needs a constructor other than a no-args constructor, you must register
|
|
||||||
* an {@link com.google.gson.InstanceCreator} for it.
|
|
||||||
*
|
|
||||||
* <p> Here is an example of how to apply this annotation to a field.
|
* <p> Here is an example of how to apply this annotation to a field.
|
||||||
* <pre>
|
* <pre>
|
||||||
* private static final class Gadget {
|
* private static final class Gadget {
|
||||||
@ -74,8 +70,11 @@ import com.google.gson.TypeAdapter;
|
|||||||
* }
|
* }
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
* The above annotation will ensure UserJsonAdapter2 takes precedence over UserJsonAdapter
|
*
|
||||||
* for the user field of the Gadget class.
|
* It's possible to specify different type adapters on a field, that
|
||||||
|
* field's type, and in the {@link com.google.gson.GsonBuilder}. Field
|
||||||
|
* annotations take precedence over {@code GsonBuilder}-registered type
|
||||||
|
* adapters, which in turn take precedence over annotated types.
|
||||||
*
|
*
|
||||||
* @since 2.3
|
* @since 2.3
|
||||||
*
|
*
|
||||||
|
@ -38,22 +38,11 @@ public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapte
|
|||||||
this.constructorConstructor = constructorConstructor;
|
this.constructorConstructor = constructorConstructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) {
|
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) {
|
||||||
Class<? super T> clazz = targetType.getRawType();
|
JsonAdapter annotation = targetType.getRawType().getAnnotation(JsonAdapter.class);
|
||||||
JsonAdapter annotation = clazz.getAnnotation(JsonAdapter.class);
|
return annotation != null
|
||||||
if (annotation == null) return null;
|
? (TypeAdapter<T>) constructorConstructor.get(TypeToken.get(annotation.value())).construct()
|
||||||
TypeAdapter adapter = getAnnotationTypeAdapter(gson, constructorConstructor, annotation);
|
: null;
|
||||||
return adapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
static TypeAdapter<?> getAnnotationTypeAdapter(Gson gson,
|
|
||||||
ConstructorConstructor constructorConstructor, JsonAdapter annotation) {
|
|
||||||
Class<? extends TypeAdapter<?>> adapterClass = annotation.value();
|
|
||||||
ObjectConstructor<? extends TypeAdapter<?>> constructor =
|
|
||||||
constructorConstructor.get(TypeToken.get(adapterClass));
|
|
||||||
TypeAdapter<?> adapter = constructor.construct();
|
|
||||||
Gson.$$Internal.addGeneratedTypeAdapter(gson, adapter);
|
|
||||||
return adapter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,12 +16,6 @@
|
|||||||
|
|
||||||
package com.google.gson.internal.bind;
|
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.FieldNamingStrategy;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonSyntaxException;
|
import com.google.gson.JsonSyntaxException;
|
||||||
@ -38,6 +32,11 @@ import com.google.gson.reflect.TypeToken;
|
|||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonToken;
|
import com.google.gson.stream.JsonToken;
|
||||||
import com.google.gson.stream.JsonWriter;
|
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.
|
* Type adapter that reflects over the fields and methods of a class.
|
||||||
@ -71,9 +70,7 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ObjectConstructor<T> constructor = constructorConstructor.get(type);
|
ObjectConstructor<T> constructor = constructorConstructor.get(type);
|
||||||
Adapter<T> adapter = new Adapter<T>(constructor, getBoundFields(gson, type, raw));
|
return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
|
||||||
Gson.$$Internal.addGeneratedTypeAdapter(gson, adapter);
|
|
||||||
return adapter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
|
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
|
||||||
@ -102,14 +99,10 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private TypeAdapter<?> getFieldAdapter(Gson gson, Field field, TypeToken<?> fieldType) {
|
private TypeAdapter<?> getFieldAdapter(Gson gson, Field field, TypeToken<?> fieldType) {
|
||||||
TypeAdapter<?> adapter = gson.getAdapter(fieldType);
|
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
|
||||||
boolean generatedAdapter = Gson.$$Internal.isGeneratedTypeAdapter(gson, adapter);
|
return (annotation != null)
|
||||||
if (generatedAdapter && field.isAnnotationPresent(JsonAdapter.class)) {
|
? constructorConstructor.get(TypeToken.get(annotation.value())).construct()
|
||||||
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
|
: gson.getAdapter(fieldType);
|
||||||
return JsonAdapterAnnotationTypeAdapterFactory.getAnnotationTypeAdapter(
|
|
||||||
gson, constructorConstructor, annotation);
|
|
||||||
}
|
|
||||||
return adapter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
|
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
|
||||||
|
@ -16,56 +16,64 @@
|
|||||||
|
|
||||||
package com.google.gson.functional;
|
package com.google.gson.functional;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.TypeAdapter;
|
import com.google.gson.TypeAdapter;
|
||||||
import com.google.gson.annotations.JsonAdapter;
|
import com.google.gson.annotations.JsonAdapter;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional tests for the {@link com.google.gson.annotations.JsonAdapter} annotation on fields.
|
* Functional tests for the {@link com.google.gson.annotations.JsonAdapter} annotation on fields.
|
||||||
*/
|
*/
|
||||||
public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
|
public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
|
||||||
|
public void testClassAnnotationAdapterTakesPrecedenceOverDefault() {
|
||||||
public void testJsonAdapterInvoked() {
|
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String json = gson.toJson(new Computer(new User("Inderjeet Singh")));
|
String json = gson.toJson(new Computer(new User("Inderjeet Singh")));
|
||||||
assertEquals("{\"user\":{\"firstName\":\"Inderjeet\",\"lastName\":\"Singh\"}}", json);
|
assertEquals("{\"user\":\"UserClassAnnotationAdapter\"}", json);
|
||||||
Computer computer = gson.fromJson("{'user':{'firstName':'Jesse','lastName':'Wilson'}}", Computer.class);
|
Computer computer = gson.fromJson("{'user':'Inderjeet Singh'}", Computer.class);
|
||||||
assertEquals("Jesse Wilson", computer.user.name);
|
assertEquals("UserClassAnnotationAdapter", computer.user.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testRegisteredTypeAdapterOverridesFieldAnnotation() {
|
public void testRegisteredTypeAdapterTakesPrecedenceOverClassAnnotationAdapter() {
|
||||||
|
Gson gson = new GsonBuilder()
|
||||||
|
.registerTypeAdapter(User.class, new RegisteredUserAdapter())
|
||||||
|
.create();
|
||||||
|
String json = gson.toJson(new Computer(new User("Inderjeet Singh")));
|
||||||
|
assertEquals("{\"user\":\"RegisteredUserAdapter\"}", json);
|
||||||
|
Computer computer = gson.fromJson("{'user':'Inderjeet Singh'}", Computer.class);
|
||||||
|
assertEquals("RegisteredUserAdapter", computer.user.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testFieldAnnotationTakesPrecedenceOverRegisteredTypeAdapter() {
|
||||||
Gson gson = new GsonBuilder()
|
Gson gson = new GsonBuilder()
|
||||||
.registerTypeAdapter(Part.class, new TypeAdapter<Part>() {
|
.registerTypeAdapter(Part.class, new TypeAdapter<Part>() {
|
||||||
@Override public void write(JsonWriter out, Part part) throws IOException {
|
@Override public void write(JsonWriter out, Part part) throws IOException {
|
||||||
out.value("registeredAdapter");
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Part read(JsonReader in) throws IOException {
|
@Override public Part read(JsonReader in) throws IOException {
|
||||||
return new Part(in.nextString());
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
}).create();
|
}).create();
|
||||||
String json = gson.toJson(new Gadget(new Part("screen")));
|
String json = gson.toJson(new Gadget(new Part("screen")));
|
||||||
assertEquals("{\"part\":\"registeredAdapter\"}", json);
|
assertEquals("{\"part\":\"PartJsonFieldAnnotationAdapter\"}", json);
|
||||||
Gadget gadget = gson.fromJson("{'part':'registeredAdapterValue'}", Gadget.class);
|
Gadget gadget = gson.fromJson("{'part':'screen'}", Gadget.class);
|
||||||
assertEquals("registeredAdapterValue", gadget.part.name);
|
assertEquals("PartJsonFieldAnnotationAdapter", gadget.part.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFieldAnnotationSupersedesClassAnnotation() {
|
public void testFieldAnnotationTakesPrecedenceOverClassAnnotation() {
|
||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String json = gson.toJson(new Computer2(new User("Inderjeet Singh")));
|
String json = gson.toJson(new Computer2(new User("Inderjeet Singh")));
|
||||||
assertEquals("{\"user\":\"userJsonAdapter2\"}", json);
|
assertEquals("{\"user\":\"UserFieldAnnotationAdapter\"}", json);
|
||||||
Computer2 target = gson.fromJson("{'user':'userJsonAdapter2Value'}", Computer2.class);
|
Computer2 target = gson.fromJson("{'user':'Interjeet Singh'}", Computer2.class);
|
||||||
assertEquals("userJsonAdapter2Value", target.user.name);
|
assertEquals("UserFieldAnnotationAdapter", target.user.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Gadget {
|
private static final class Gadget {
|
||||||
@JsonAdapter(PartJsonAdapter.class)
|
@JsonAdapter(PartJsonFieldAnnotationAdapter.class)
|
||||||
final Part part;
|
final Part part;
|
||||||
Gadget(Part part) {
|
Gadget(Part part) {
|
||||||
this.part = part;
|
this.part = part;
|
||||||
@ -79,13 +87,13 @@ public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PartJsonAdapter extends TypeAdapter<Part> {
|
private static class PartJsonFieldAnnotationAdapter extends TypeAdapter<Part> {
|
||||||
@Override public void write(JsonWriter out, Part part) throws IOException {
|
@Override public void write(JsonWriter out, Part part) throws IOException {
|
||||||
out.value(part.name);
|
out.value("PartJsonFieldAnnotationAdapter");
|
||||||
}
|
}
|
||||||
@Override public Part read(JsonReader in) throws IOException {
|
@Override public Part read(JsonReader in) throws IOException {
|
||||||
in.nextString();
|
in.nextString();
|
||||||
return new Part("partJsonAdapter");
|
return new Part("PartJsonFieldAnnotationAdapter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +104,7 @@ public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonAdapter(UserJsonAdapter.class)
|
@JsonAdapter(UserClassAnnotationAdapter.class)
|
||||||
private static class User {
|
private static class User {
|
||||||
public final String name;
|
public final String name;
|
||||||
private User(String name) {
|
private User(String name) {
|
||||||
@ -104,43 +112,42 @@ public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class UserJsonAdapter extends TypeAdapter<User> {
|
private static class UserClassAnnotationAdapter extends TypeAdapter<User> {
|
||||||
@Override public void write(JsonWriter out, User user) throws IOException {
|
@Override public void write(JsonWriter out, User user) throws IOException {
|
||||||
// implement write: combine firstName and lastName into name
|
out.value("UserClassAnnotationAdapter");
|
||||||
out.beginObject();
|
|
||||||
String[] parts = user.name.split(" ");
|
|
||||||
out.name("firstName");
|
|
||||||
out.value(parts[0]);
|
|
||||||
out.name("lastName");
|
|
||||||
out.value(parts[1]);
|
|
||||||
out.endObject();
|
|
||||||
}
|
}
|
||||||
@Override public User read(JsonReader in) throws IOException {
|
@Override public User read(JsonReader in) throws IOException {
|
||||||
// implement read: split name into firstName and lastName
|
in.nextString();
|
||||||
in.beginObject();
|
return new User("UserClassAnnotationAdapter");
|
||||||
in.nextName();
|
|
||||||
String firstName = in.nextString();
|
|
||||||
in.nextName();
|
|
||||||
String lastName = in.nextString();
|
|
||||||
in.endObject();
|
|
||||||
return new User(firstName + " " + lastName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Computer2 {
|
private static final class Computer2 {
|
||||||
// overrides the JsonAdapter annotation of User with this
|
// overrides the JsonAdapter annotation of User with this
|
||||||
@JsonAdapter(UserJsonAdapter2.class)
|
@JsonAdapter(UserFieldAnnotationAdapter.class)
|
||||||
final User user;
|
final User user;
|
||||||
Computer2(User user) {
|
Computer2(User user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static final class UserJsonAdapter2 extends TypeAdapter<User> {
|
|
||||||
|
private static final class UserFieldAnnotationAdapter extends TypeAdapter<User> {
|
||||||
@Override public void write(JsonWriter out, User user) throws IOException {
|
@Override public void write(JsonWriter out, User user) throws IOException {
|
||||||
out.value("userJsonAdapter2");
|
out.value("UserFieldAnnotationAdapter");
|
||||||
}
|
}
|
||||||
@Override public User read(JsonReader in) throws IOException {
|
@Override public User read(JsonReader in) throws IOException {
|
||||||
return new User(in.nextString());
|
in.nextString();
|
||||||
|
return new User("UserFieldAnnotationAdapter");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class RegisteredUserAdapter extends TypeAdapter<User> {
|
||||||
|
@Override public void write(JsonWriter out, User user) throws IOException {
|
||||||
|
out.value("RegisteredUserAdapter");
|
||||||
|
}
|
||||||
|
@Override public User read(JsonReader in) throws IOException {
|
||||||
|
in.nextString();
|
||||||
|
return new User("RegisteredUserAdapter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,12 +155,12 @@ public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
|
|||||||
Gson gson = new Gson();
|
Gson gson = new Gson();
|
||||||
String json = "{'part1':'name','part2':{'name':'name2'}}";
|
String json = "{'part1':'name','part2':{'name':'name2'}}";
|
||||||
GadgetWithTwoParts gadget = gson.fromJson(json, GadgetWithTwoParts.class);
|
GadgetWithTwoParts gadget = gson.fromJson(json, GadgetWithTwoParts.class);
|
||||||
assertEquals("partJsonAdapter", gadget.part1.name);
|
assertEquals("PartJsonFieldAnnotationAdapter", gadget.part1.name);
|
||||||
assertEquals("name2", gadget.part2.name);
|
assertEquals("name2", gadget.part2.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class GadgetWithTwoParts {
|
private static final class GadgetWithTwoParts {
|
||||||
@JsonAdapter(PartJsonAdapter.class) final Part part1;
|
@JsonAdapter(PartJsonFieldAnnotationAdapter.class) final Part part1;
|
||||||
final Part part2; // Doesn't have the JsonAdapter annotation
|
final Part part2; // Doesn't have the JsonAdapter annotation
|
||||||
@SuppressWarnings("unused") GadgetWithTwoParts(Part part1, Part part2) {
|
@SuppressWarnings("unused") GadgetWithTwoParts(Part part1, Part part2) {
|
||||||
this.part1 = part1;
|
this.part1 = part1;
|
||||||
|
Loading…
Reference in New Issue
Block a user