public final class RuntimeTypeAdapterFactory<T>
extends java.lang.Object
implements com.google.gson.TypeAdapterFactory
abstract class Shape {
int x;
int y;
}
class Circle extends Shape {
int radius;
}
class Rectangle extends Shape {
int width;
int height;
}
class Diamond extends Shape {
int width;
int height;
}
class Drawing {
Shape bottomShape;
Shape topShape;
}
Without additional type information, the serialized JSON is ambiguous. Is the bottom shape in this drawing a rectangle or a diamond?
{
"bottomShape": {
"width": 10,
"height": 5,
"x": 0,
"y": 0
},
"topShape": {
"radius": 2,
"x": 4,
"y": 1
}
}
This class addresses this problem by adding type information to the serialized JSON and honoring
that type information when the JSON is deserialized:
{
"bottomShape": {
"type": "Diamond",
"width": 10,
"height": 5,
"x": 0,
"y": 0
},
"topShape": {
"type": "Circle",
"radius": 2,
"x": 4,
"y": 1
}
}
Both the type field name ("type") and the type labels ("Rectangle") are
configurable.
RuntimeTypeAdapterFactory by passing the base type and type field name to the
of(java.lang.Class<T>, java.lang.String, boolean) factory method. If you don't supply an explicit type field name, "type" will
be used.
RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory
= RuntimeTypeAdapterFactory.of(Shape.class, "type");
Next register all of your subtypes. Every subtype must be explicitly registered. This protects
your application from injection attacks. If you don't supply an explicit type label, the type's
simple name will be used.
shapeAdapterFactory.registerSubtype(Rectangle.class, "Rectangle");
shapeAdapterFactory.registerSubtype(Circle.class, "Circle");
shapeAdapterFactory.registerSubtype(Diamond.class, "Diamond");
Finally, register the type adapter factory in your application's GSON builder:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(shapeAdapterFactory)
.create();
Like GsonBuilder, this API supports chaining:
RuntimeTypeAdapterFactory<Shape> shapeAdapterFactory = RuntimeTypeAdapterFactory.of(Shape.class)
.registerSubtype(Rectangle.class)
.registerSubtype(Circle.class)
.registerSubtype(Diamond.class);
Diamond diamond = new Diamond();
String json = gson.toJson(diamond, Shape.class);
And then:
Shape shape = gson.fromJson(json, Shape.class);
| Modifier and Type | Method and Description |
|---|---|
<R> com.google.gson.TypeAdapter<R> |
create(com.google.gson.Gson gson,
com.google.gson.reflect.TypeToken<R> type) |
static <T> RuntimeTypeAdapterFactory<T> |
of(java.lang.Class<T> baseType)
Creates a new runtime type adapter for
baseType using "type" as the type field
name. |
static <T> RuntimeTypeAdapterFactory<T> |
of(java.lang.Class<T> baseType,
java.lang.String typeFieldName)
Creates a new runtime type adapter for
baseType using typeFieldName as the type
field name. |
static <T> RuntimeTypeAdapterFactory<T> |
of(java.lang.Class<T> baseType,
java.lang.String typeFieldName,
boolean maintainType)
Creates a new runtime type adapter for
baseType using typeFieldName as the type
field name. |
RuntimeTypeAdapterFactory<T> |
recognizeSubtypes()
Ensures that this factory will handle not just the given
baseType, but any subtype of
that type. |
RuntimeTypeAdapterFactory<T> |
registerSubtype(java.lang.Class<? extends T> type)
Registers
type identified by its simple name. |
RuntimeTypeAdapterFactory<T> |
registerSubtype(java.lang.Class<? extends T> type,
java.lang.String label)
Registers
type identified by label. |
public static <T> RuntimeTypeAdapterFactory<T> of(java.lang.Class<T> baseType, java.lang.String typeFieldName, boolean maintainType)
baseType using typeFieldName as the type
field name. Type field names are case sensitive.maintainType - true if the type field should be included in deserialized objectspublic static <T> RuntimeTypeAdapterFactory<T> of(java.lang.Class<T> baseType, java.lang.String typeFieldName)
baseType using typeFieldName as the type
field name. Type field names are case sensitive.public static <T> RuntimeTypeAdapterFactory<T> of(java.lang.Class<T> baseType)
baseType using "type" as the type field
name.@CanIgnoreReturnValue public RuntimeTypeAdapterFactory<T> recognizeSubtypes()
baseType, but any subtype of
that type.@CanIgnoreReturnValue public RuntimeTypeAdapterFactory<T> registerSubtype(java.lang.Class<? extends T> type, java.lang.String label)
type identified by label. Labels are case sensitive.java.lang.IllegalArgumentException - if either type or label have already been
registered on this type adapter.@CanIgnoreReturnValue public RuntimeTypeAdapterFactory<T> registerSubtype(java.lang.Class<? extends T> type)
type identified by its simple name. Labels are
case sensitive.java.lang.IllegalArgumentException - if either type or its simple name have already been
registered on this type adapter.public <R> com.google.gson.TypeAdapter<R> create(com.google.gson.Gson gson,
com.google.gson.reflect.TypeToken<R> type)
create in interface com.google.gson.TypeAdapterFactory