当前位置: 首页 > 知识库问答 >
问题:

GSON TypeAdapter:基于“type”字段反序列化多态对象

通飞尘
2023-03-14
class BaseTypeDeserializer implements JsonDeserializer<BaseType> {
    private static final String TYPE_FIELD = "type";

    @Override
    public BaseType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonObject() && json.getAsJsonObject().has(TYPE_FIELD)) {
            JsonObject jsonObject = json.getAsJsonObject();
            final String type = jsonObject.get(TYPE_FIELD).getAsString();
            if ("type_a".equals(type)) {
                return context.deserialize(json, AType.class);
            } else if ("type_b".equals(type)) {
                return context.deserialize(json, BType.class);
            } ...

            // If you need to deserialize as BaseType,
            // deserialize without the current context
            // or you will infinite loop
            return new Gson().fromJson(json, typeOfT);

        } else {
            // Return a blank object on error
            return new BaseType();
        }
    }
}

这里有人知道如何使用TypeAdapterFactory基于“type”字段进行反序列化而不需要将整个json流读取到JsonElement对象树中吗?

共有1个答案

徐新荣
2023-03-14

>

  • 只有当反序列化数据中有baseType或子类时,才应运行自定义反序列化程序,而不是每个请求。您根据类型注册它,并且只有当gson需要序列化该类型时才调用它。

    您是否反序列化baseType以及子类?如果是这样,这一行会影响你的表现--

    返回new Gson().fromjson(json,typeOfT);

    如果您的子类相似,并且它们之间没有任何字段冲突(字段名称相同但类型不同),则可以使用包含所有字段的data transfer对象。使用gson对其进行反序列化,然后使用它创建对象。

    public class MyDTO {
       String type;
       // Fields from BaseType
       String fromBase;
       // Fields from TypeA
       String fromA;
       // Fields from TypeB
       // ...
    }
    
    
    public class BaseType {
      String type;
      String fromBase;
    
      public BaseType(MyDTO dto) {
        type = dto.type;
        fromBase = dto.fromBase;
      }
    }
    
    public class TypeA extends BaseType {
      String fromA;
    
      public TypeA(MyDTO dto) {
        super(dto);
        fromA = dto.fromA;
      }
    }
    

    然后,您可以创建typeadapterFactory,该typeadapterFactory处理从DTO到对象的转换-

    public class BaseTypeAdapterFactory implements TypeAdapterFactory {
    
      public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
        if(BaseType.class.isAssignableFrom(type.getRawType())) {
          TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
          return newItemAdapter((TypeAdapter<BaseType>) delegate,
              gson.getAdapter(new TypeToken<MyDTO>(){}));
        } else {
          return null;
        }
      }
    
      private TypeAdapter newItemAdapter(
          final TypeAdapter<BaseType> delagateAdapter,
          final TypeAdapter<MyDTO> dtoAdapter) {
        return new TypeAdapter<BaseType>() {
    
          @Override
          public void write(JsonWriter out, BaseType value) throws IOException {
            delagateAdapter.write(out, value);
          }
    
          @Override
          public BaseType read(JsonReader in) throws IOException {
            MyDTO dto = dtoAdapter.read(in);
            if("base".equals(dto.type)) {
              return new BaseType(dto);
            } else if ("type_a".equals(dto.type)) {
              return new TypeA(dto);
            } else {
              return null;
            }
          }
        };
      }
    }
    

    像这样使用--

    Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(new BaseTypeAdapterFactory())
        .create();
    
    BaseType base = gson.fromJson(baseString, BaseType.class);
    

  •  类似资料:
    • 我的RESTendpoint返回包含对象字段的响应对象。序列化一切正常,但当我开始为此API编写客户端时,我遇到了反序列化问题。我根据一些关于使用Jackson进行多态序列化的问题/文章制作了这个示例代码。它演示了这个问题。 我的期望(以及我对列表的期望 我现在拥有的Object: 但我需要反序列化除动物列表之外的其他类型的对象。救命啊!

    • 我正在使用JacksonPolymorphicDeserialization,这是我的代码,它反序列化到基于“type”属性的适当类中: 它工作得很好,我的json根据“type”值变成了预期的类。 但是,我正在考虑将“type”属性从String移动到Enum,这是我的新代码,带有以下更改: 和枚举: 问题是,第二种方法不起作用。。。知道为什么吗???我可以在这里使用Enum吗??? 谢谢!

    • Jackson版本:2.10.1 谢谢你的回答!

    • 我正在尝试为接受JSON输入的前端库创建一个java SDK。本质上,此SDK将特定类型的对象转换为JSON,然后由前端库使用。 我正在使用杰克逊的多态序列化/反序列化使用它的注释系统。 我有一个基类a和扩展a的两个子类B和C。类a有一个类型字段,我用它来决定要使用哪个类(B或C)。语法如下所示: 现在,当我使用Jackson的ObjectMapper函数读取字符串化的JSON并转换为类A时,我根

    • 我有一个杰克逊多态性问题。我想将JSON数据反序列化为多态类型。通过阅读Jackson文档,我可以将JSON数据反序列化为多态类型。不过,我有一个特例。我有一个类结构如下: 注意:类栏除了继承的“类型”字段之外没有任何其他成员变量。 如果我传入上面的json数据,如: 我得到了类似“无法从end_token中反序列化类条”的信息。我相信这是因为JsonTypeInfo和JsonSubTypes注释

    • 我对Jackson和类型层次结构有以下问题。我正在序列化一个类SubA,该类将扩展为一个字符串,然后尝试将其反序列化回来。当然,在编译时,系统不知道它是基还是SubA,因此我希望它是基,如果它是SubA,则会在编译后执行一些其他操作。 我的基本类看起来像: ...和一个派生自的类: ... 我试图执行以下代码: String是: 但我一次又一次地犯同样的错误。映射器现在知道如何处理另一个类参数-它