PolymorphicJsonAdapterFactory

class PolymorphicJsonAdapterFactory<T> : JsonAdapter.Factory

A JsonAdapter factory for objects that include type information in the JSON. When decoding JSON Moshi uses this type information to determine which class to decode to. When encoding Moshi uses the object’s class to determine what type information to include.

Suppose we have an interface, its implementations, and a class that uses them:


interface HandOfCards {
}

class BlackjackHand implements HandOfCards {
  Card hidden_card;
  List<Card> visible_cards;
}

class HoldemHand implements HandOfCards {
  Set<Card> hidden_cards;
}

class Player {
  String name;
  HandOfCards hand;
}

We want to decode the following JSON into the player model above:


{
  "name": "Jesse",
  "hand": {
    "hand_type": "blackjack",
    "hidden_card": "9D",
    "visible_cards": ["8H", "4C"]
  }
}

Left unconfigured, Moshi would incorrectly attempt to decode the hand object to the abstract HandOfCards interface. We configure it to use the appropriate subtype instead:


Moshi moshi = new Moshi.Builder()
    .add(PolymorphicJsonAdapterFactory.of(HandOfCards.class, "hand_type")
        .withSubtype(BlackjackHand.class, "blackjack")
        .withSubtype(HoldemHand.class, "holdem"))
    .build();

This class imposes strict requirements on its use:

  • Base types may be classes or interfaces.
  • Subtypes must encode as JSON objects.
  • Type information must be in the encoded object. Each message must have a type label like hand_type whose value is a string like blackjack that identifies which type to use.
  • Each type identifier must be unique.

For best performance type information should be the first field in the object. Otherwise Moshi must reprocess the JSON stream once it knows the object's type.

If an unknown subtype is encountered when decoding:

  • If withDefaultValue is used, then defaultValue will be returned.
  • If withFallbackJsonAdapter is used, then the fallbackJsonAdapter.fromJson(reader) result will be returned.
  • Otherwise a JsonDataException will be thrown.

If an unknown type is encountered when encoding:

If the same subtype has multiple labels the first one is used when encoding.

Functions

Link copied to clipboard
open fun create(    type: Type,     annotations: Set<out Annotation>,     moshi: Moshi): JsonAdapter<out Any>
Link copied to clipboard
open fun <T> of(baseType: Class<T>, labelKey: String): PolymorphicJsonAdapterFactory<T>
Link copied to clipboard
open fun withDefaultValue(@Nullable defaultValue: T): PolymorphicJsonAdapterFactory<T>
Returns a new factory that will default to defaultValue upon decoding of unrecognized labels.
Link copied to clipboard
open fun withFallbackJsonAdapter(@Nullable fallbackJsonAdapter: JsonAdapter<Any>): PolymorphicJsonAdapterFactory<T>
Returns a new factory that with default to fallbackJsonAdapter.fromJson(reader) upon decoding of unrecognized labels.
Link copied to clipboard
open fun withSubtype(subtype: Class<out T>, label: String): PolymorphicJsonAdapterFactory<T>
Returns a new factory that decodes instances of subtype.