Creates type adapters for set of related types. Type adapter factories are most useful when several types share similar structure in their JSON form.
Example: Converting enums to lowercase
In this example, we implement a factory that creates type adapters for all enums. The type adapters will write enums in lowercase, despite the fact that they're defined in {@code CONSTANT_CASE} in the corresponding Javamodel:
{@code}public class LowercaseEnumTypeAdapterFactory implements TypeAdapterFactory public TypeAdapter create(Gson gson, TypeToken type) { Class rawType = (Class) type.getRawType(); if (!rawType.isEnum()) { return null; } final Map lowercaseToConstant = new HashMap(); for (T constant : rawType.getEnumConstants()) { lowercaseToConstant.put(toLowercase(constant), constant); } return new TypeAdapter() { public void write(JsonWriter out, T value) throws IOException { if (value == null) { out.nullValue(); } else { out.value(toLowercase(value)); } } public T read(JsonReader reader) throws IOException { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return null; } else { return lowercaseToConstant.get(reader.nextString()); } } }; } private String toLowercase(Object o) { return o.toString().toLowerCase(Locale.US); } } }
Type adapter factories select which types they provide type adapters for. If a factory cannot support a given type, it must return null when that type is passed to {@link #create}. Factories should expect {@code create()} to be called on them for many types and should return null formost of those types. In the above example the factory returns null for calls to {@code create()} where {@code type} is not an enum.
A factory is typically called once per type, but the returned type adapter may be used many times. It is most efficient to do expensive work like reflection in {@code create()} so that the type adapter's {@code read()} and {@code write()} methods can be very fast. In this example themapping from lowercase name to enum value is computed eagerly.
As with type adapters, factories must be registered with a {@link com.google.gson.GsonBuilder} for them to take effect:
{@code GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory()); ... Gson gson = builder.create();}
If multiple factories support the same type, the factory registered earlier takes precedence.
Example: composing other type adapters
In this example we implement a factory for Guava's {@code Multiset}collection type. The factory can be used to create type adapters for multisets of any element type: the type adapter for {@code Multiset
} is different from the type adapter for {@code Multiset}. The type adapter delegates to another type adapter for the multiset elements. It figures out the element type by reflecting on the multiset's type token. A {@code Gson} is passed in to {@code create} forjust this purpose:
{@code}public class MultisetTypeAdapterFactory implements TypeAdapterFactory public TypeAdapter create(Gson gson, TypeToken typeToken) { Type type = typeToken.getType(); if (typeToken.getRawType() != Multiset.class || !(type instanceof ParameterizedType)) { return null; } Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0]; TypeAdapter> elementAdapter = gson.getAdapter(TypeToken.get(elementType)); return (TypeAdapter) newMultisetAdapter(elementAdapter); } private TypeAdapter> newMultisetAdapter( final TypeAdapter elementAdapter) { return new TypeAdapter>() { public void write(JsonWriter out, Multiset value) throws IOException { if (value == null) { out.nullValue(); return; } out.beginArray(); for (Multiset.Entry entry : value.entrySet()) { out.value(entry.getCount()); elementAdapter.write(out, entry.getElement()); } out.endArray(); } public Multiset read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } Multiset result = LinkedHashMultiset.create(); in.beginArray(); while (in.hasNext()) { int count = in.nextInt(); E element = elementAdapter.read(in); result.add(element, count); } in.endArray(); return result; } }; } } }
Delegating from one type adapter to another is extremely powerful; it's the foundation of how Gson converts Java objects and collections. Whenever possible your factory should retrieve its delegate type adapter in the {@code create()} method; this ensures potentially-expensive type adaptercreation happens only once.
@since 2.1