InstanceCreator在 Gson 中不常用,Gson 建议在这种情况下造成一些混乱,通常可以用类型适配器(工厂)替换。该InstanceCreator接口只能创建一个不会与您尝试反序列化的 JSON 合并的默认实例。例如:
{
"name": "13289/john-doe",
"human_variable": "John Doe"
}
public static Human create() {
return new AutoValue_Human("anonymous", null);
}
private static final Gson gson = new GsonBuilder()
.registerTypeAdapter(Species.class, (InstanceCreator<Species>) type -> Human.create())
.create();
final Species species = gson.fromJson(jsonReader, Species.class);
System.out.println(species.name());
输出:
匿名的
在这种情况下,您只需将Species接口与默认Human实例绑定。据此,species.name()将anonymous只返回无论 JSON (Gson 内部ReflectiveTypeAdapterFactory.Adapter只是跳过所有 JSON 字段(实际上,它首先针对给定的字段声明类型收集所有字段,而不是在InstanceCreator创建 -created 实例之后的实际对象类型),因为它是一个接口- 虽然不确定这是否不是错误)。
您真正需要的是以下步骤:
com.ryanharter.auto.value:auto-value-gson:...如果您还没有使用,请使用。
- 注册使用扩展
Human创建的类型适配器工厂。auto-value-gson
- 将您的 JSON 反序列化为具体
Human实例而不是Species实例。
例如:
@GsonTypeAdapterFactory
abstract class HumanAdapterFactory
implements TypeAdapterFactory {
public static TypeAdapterFactory create() {
return new AutoValueGson_HumanAdapterFactory();
}
}
private static final Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(HumanAdapterFactory.create())
.create();
final Human human = gson.fromJson(jsonReader, Human.class);
System.out.println(human.name());
System.out.println(human.humanVariable());
输出:
13289/john-doe
约翰·多伊
这是我最推荐的解决方案。
如果出于任何正当理由,您确实需要将 JSON 反序列化为未知Species实例并动态解析其类型,则可以创建更复杂的解决方案。它的“经典”解决方案之一是通过其特殊的 JSON 属性解析对象类型(受来自 Gson extras 的RuntimeTypeAdapterFactory的启发,但未作为工件发布):
{
"type": "human",
"name": "13289/john-doe",
"human_variable": "John Doe"
}
private static final Gson gson = new GsonBuilder()
// We'll ask Gson for it ourselves
.registerTypeAdapterFactory(HumanAdapterFactory.create())
.registerTypeAdapterFactory(new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Check whether we can support the given type
if ( Species.class.isAssignableFrom(typeToken.getRawType()) ) {
final TypeAdapterFactory currentTypeAdapterFactory = this;
// And get the "original" type adapter
@SuppressWarnings("unchecked")
final TypeAdapter<Species> delegateTypeAdapter = (TypeAdapter<Species>) gson.getDelegateAdapter(this, typeToken);
final TypeAdapter<Species> speciesTypeAdapter = new TypeAdapter<Species>() {
// Type tokens can be static since they are immutabe
private /*static*/ final TypeToken<Human> humanTypeToken = TypeToken.get(Human.class);
// JsonParser seems to be immutable as well
private /*static*/ final JsonParser jsonParser = new JsonParser();
@Override
public void write(final JsonWriter out, final Species value)
throws IOException {
delegateTypeAdapter.write(out, value);
}
@Override
public Species read(final JsonReader in)
throws IOException {
// Caching the current value to a JSON tree
final JsonElement jsonElement = jsonParser.parse(in);
final String type = jsonElement.getAsJsonObject()
.getAsJsonPrimitive("type")
.getAsString();
final TypeAdapter<? extends Species> typeAdapter;
// Now trying to resolve an appropriate type adapter
switch ( type ) {
case "human":
typeAdapter = gson.getDelegateAdapter(currentTypeAdapterFactory, humanTypeToken);
break;
default:
throw new MalformedJsonException("Unknown type: " + type);
}
// At this point the JsonReader is moved formed due to the previous read, but we have the JSON tree
return typeAdapter.fromJsonTree(jsonElement);
}
}.nullSafe();
@SuppressWarnings("unchecked")
final TypeAdapter<T> castSpeciesTypeAdapter = (TypeAdapter<T>) speciesTypeAdapter;
return castSpeciesTypeAdapter;
}
return null;
}
})
.create();
final Species species = gson.fromJson(jsonReader, Species.class);
System.out.println(species.getClass());
System.out.println(species.name());
输出:
类 q43267910.AutoValue_Human
13289/john-doe