diff --git a/adapters/src/main/java/com/squareup/moshi/adapters/RuntimeJsonAdapterFactory.java b/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java
similarity index 67%
rename from adapters/src/main/java/com/squareup/moshi/adapters/RuntimeJsonAdapterFactory.java
rename to adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java
index 9c9d41d..de0ca32 100644
--- a/adapters/src/main/java/com/squareup/moshi/adapters/RuntimeJsonAdapterFactory.java
+++ b/adapters/src/main/java/com/squareup/moshi/adapters/PolymorphicJsonAdapterFactory.java
@@ -31,28 +31,84 @@ import java.util.Set;
import javax.annotation.CheckReturnValue;
/**
- * A JsonAdapter factory for polymorphic types. This is useful when the type is not known before
- * decoding the JSON. This factory's adapters expect JSON in the format of a JSON object with a
- * key whose value is a label that determines the type to which to map the JSON object. To use, add
- * this factory to your {@link Moshi.Builder}:
+ * 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:
+ *
+ *
Left unconfigured, Moshi would incorrectly attempt to decode the hand object to the abstract
+ * {@code HandOfCards} interface. We configure it to use the appropriate subtype instead:
*
*
This class imposes strict requirements on its use:
+ *
+ *
+ *
Base types may be classes or interfaces. You may not use {@code Object.class} as a base
+ * type.
+ *
Subtypes must encode as JSON objects.
+ *
Type information must be in the encoded object. Each message must have a type label like
+ * {@code hand_type} whose value is a string like {@code 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, this will throw a {@link
+ * JsonDataException}. If an unknown type is encountered when encoding, this will throw an {@link
+ * IllegalArgumentException}.
*/
-
-public final class RuntimeJsonAdapterFactory implements JsonAdapter.Factory {
+public final class PolymorphicJsonAdapterFactory implements JsonAdapter.Factory {
final Class baseType;
final String labelKey;
final List labels;
final List subtypes;
- RuntimeJsonAdapterFactory(
+ PolymorphicJsonAdapterFactory(
Class baseType, String labelKey, List labels, List subtypes) {
this.baseType = baseType;
this.labelKey = labelKey;
@@ -66,14 +122,14 @@ public final class RuntimeJsonAdapterFactory implements JsonAdapter.Factory {
* JSON object.
*/
@CheckReturnValue
- public static RuntimeJsonAdapterFactory of(Class baseType, String labelKey) {
+ public static PolymorphicJsonAdapterFactory of(Class baseType, String labelKey) {
if (baseType == null) throw new NullPointerException("baseType == null");
if (labelKey == null) throw new NullPointerException("labelKey == null");
if (baseType == Object.class) {
throw new IllegalArgumentException(
"The base type must not be Object. Consider using a marker interface.");
}
- return new RuntimeJsonAdapterFactory<>(
+ return new PolymorphicJsonAdapterFactory<>(
baseType, labelKey, Collections.emptyList(), Collections.emptyList());
}
@@ -82,7 +138,7 @@ public final class RuntimeJsonAdapterFactory implements JsonAdapter.Factory {
* during encoding an {@linkplain IllegalArgumentException} will be thrown. When an unknown label
* is found during decoding a {@linkplain JsonDataException} will be thrown.
*/
- public RuntimeJsonAdapterFactory withSubtype(Class extends T> subtype, String label) {
+ public PolymorphicJsonAdapterFactory withSubtype(Class extends T> subtype, String label) {
if (subtype == null) throw new NullPointerException("subtype == null");
if (label == null) throw new NullPointerException("label == null");
if (labels.contains(label) || subtypes.contains(subtype)) {
@@ -92,7 +148,7 @@ public final class RuntimeJsonAdapterFactory implements JsonAdapter.Factory {
newLabels.add(label);
List newSubtypes = new ArrayList<>(subtypes);
newSubtypes.add(subtype);
- return new RuntimeJsonAdapterFactory<>(baseType, labelKey, newLabels, newSubtypes);
+ return new PolymorphicJsonAdapterFactory<>(baseType, labelKey, newLabels, newSubtypes);
}
@Override
@@ -107,11 +163,11 @@ public final class RuntimeJsonAdapterFactory implements JsonAdapter.Factory {
}
JsonAdapter