diff --git a/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java b/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java index bc0569cb..45d143aa 100644 --- a/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java +++ b/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java @@ -126,21 +126,32 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { private final String typeFieldName; private final Map> labelToSubtype = new LinkedHashMap>(); private final Map, String> subtypeToLabel = new LinkedHashMap, String>(); + private final boolean maintainType; - private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName) { + private RuntimeTypeAdapterFactory(Class baseType, String typeFieldName, boolean maintainType) { if (typeFieldName == null || baseType == null) { throw new NullPointerException(); } this.baseType = baseType; this.typeFieldName = typeFieldName; + this.maintainType = maintainType; } + /** + * Creates a new runtime type adapter using for {@code baseType} using {@code + * typeFieldName} as the type field name. Type field names are case sensitive. + * {@code maintainType} flag decide if the type will be stored in pojo or not. + */ + public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName, boolean maintainType) { + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, maintainType); + } + /** * Creates a new runtime type adapter using for {@code baseType} using {@code * typeFieldName} as the type field name. Type field names are case sensitive. */ public static RuntimeTypeAdapterFactory of(Class baseType, String typeFieldName) { - return new RuntimeTypeAdapterFactory(baseType, typeFieldName); + return new RuntimeTypeAdapterFactory(baseType, typeFieldName, false); } /** @@ -148,7 +159,7 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { * the type field name. */ public static RuntimeTypeAdapterFactory of(Class baseType) { - return new RuntimeTypeAdapterFactory(baseType, "type"); + return new RuntimeTypeAdapterFactory(baseType, "type", false); } /** @@ -199,7 +210,13 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { return new TypeAdapter() { @Override public R read(JsonReader in) throws IOException { JsonElement jsonElement = Streams.parse(in); - JsonElement labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + JsonElement labelJsonElement; + if (maintainType) { + labelJsonElement = jsonElement.getAsJsonObject().get(typeFieldName); + } else { + labelJsonElement = jsonElement.getAsJsonObject().remove(typeFieldName); + } + if (labelJsonElement == null) { throw new JsonParseException("cannot deserialize " + baseType + " because it does not define a field named " + typeFieldName); @@ -224,12 +241,16 @@ public final class RuntimeTypeAdapterFactory implements TypeAdapterFactory { + "; did you forget to register a subtype?"); } JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject(); - if (jsonObject.has(typeFieldName)) { - throw new JsonParseException("cannot serialize " + srcType.getName() - + " because it already defines a field named " + typeFieldName); - } JsonObject clone = new JsonObject(); - clone.add(typeFieldName, new JsonPrimitive(label)); + + if (!maintainType) { + if (jsonObject.has(typeFieldName)) { + throw new JsonParseException("cannot serialize " + srcType.getName() + + " because it already defines a field named " + typeFieldName); + } + clone.add(typeFieldName, new JsonPrimitive(label)); + } + for (Map.Entry e : jsonObject.entrySet()) { clone.add(e.getKey(), e.getValue()); }