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

如何在没有注释和mixin的情况下实现多态序列化

贺浩壤
2023-03-14

在jackson中,我们可以使用注释

  1. @Json类型信息
  2. @Json子类型
  3. @JsonSubTypes.类型

以实现多态序列化。

我们可以选择

  1. 直接在数据模型上使用这些注释,这是最简单的方法。
  2. 在mixin上使用这些注释。这是一个关于它的链接Jackson中的多态反序列化,没有注释。

这两种解决方案都有一个问题:编写代码时必须知道所有子类。

在GraphQL中

  1. 鉴别器字段固定:"__typename"
  2. 子类型名称也是固定的:java类的简单名称

所有要求都是固定的,这意味着不需要逐个配置子类型,可以创建一个杰克逊模块来自动处理它们。

// An empty interface
// Developers need not to configure polymorphic metadata for any class of its subtypes 
public interface GraphQLObject {}

public class BookStore implements GraphQLObject {
    public List<Book> getBooks() {...}
    ...other gettes/setters...
}
public abstract class Book implements GraphQLObject {
    ... some properties ...
}
public class ElectronicBook extends Book {
    ... some properties ...
}
public class PaperBook extends Book {
    ... some properties ...
}

用法代码如下所示

BookStore store = ...;
ObjectMapper mapper = new ObjectMapper();
mapper.addModule(new GraphQLModule());
System.out.println(mapper.writeValueAsString(store));

在这里,我们需要创建"GraphQLModule",它可以处理实现空接口的所有子类型"GraphQLObject",并告诉jackson如何使用每个子类型的简单类名作为鉴别器字段"__typename"的值

结果如下:

{
   name: "store",
   books: [
     { __typename: "ElectronicBook", name: "book-1" },
     { __typename: "PaperBook", name: "book-2" }
   ]
}

是否可以实现“GraphQLModule”?

注意:

像jackson的默认多态行为一样,鉴别器字段只需要在对象运行时类型与编译时已知的list的泛型类型参数不同时添加。

共有2个答案

鲜于勇
2023-03-14

可以实现扩展简单模块类的“图形QL模块”模块:

public class GraphQLModule extends SimpleModule {

    public GraphQLModule() {
        this.addSerializer(new GraphQLSerializer());
    }
}

我在模块中添加了一个新的序列化程序,它扩展了< code>StdSerializer类:

public class GraphQLSerializer extends StdSerializer<GraphQLObject> {

    public GraphQLSerializer() {
        super(GraphQLObject.class);
    }

    @Override
    public void serialize(GraphQLObject obj, JsonGenerator jg, SerializerProvider sp) throws IOException {
        jg.writeStartObject();
        jg.writeStringField("__typename", obj.getClass().getSimpleName());
        jg.writeEndObject();
    }
    
}

<code>GraphQLSerializer</code>序列化程序只需将实现<code>GraphQLObject</ccode>接口的对象序列化,并在json中仅将对象的类名字符串作为<code>__typename</code>包含在内。

因此,您可以将注册此模块添加到您的objectMapper并像在此示例中一样使用它:

public interface GraphQLObject {}
public abstract class Book implements GraphQLObject {}
public class ElectronicBook extends Book {}
public class PaperBook extends Book {}

ObjectMapper objectMapper = new ObjectMapper();
mapper.registerModule(new GraphQLModule());
List<Book> books = List.of(new ElectronicBook(), new PaperBook());
//it will print [{"__typename":"ElectronicBook"},{"__typename":"PaperBook"}]
System.out.println(mapper.writeValueAsString(books));
令狐凌
2023-03-14

我找到了原因。

我试图定义客户序列化程序,但我发现“序列化与类型”从未被调用。

在我的项目中,数据类型是接口。我使用ASM来生成其字节码。我只生成了最简单的字节码,忽略了泛型的签名。

所以,在整体中,它是列表

但是,在我的字节码实现中,它是List

 类似资料:
  • 我有以下2个实体: 它们有共享字段/列,例如:等,但是每个主键id字段的名称不同,例如有和 有没有一种方法可以创建一个基本实体超类来保存这些通用的

  • 所以我想要一个“Void Repository”,通过它可以访问不一定在实体上操作的存储过程。 但这当然不起作用,因为期望是一个实体。 有没有一种方法可以使用注释而无需创建虚拟实体,或者我是否坚持使用使用通过准备好的语句进行查询的已实现类? 因为老实说,这很难看:

  • 我试图了解DI在我们的代码库(Kotlin)中是如何使用的。我们正在使用googleguice进行依赖注入。 下面是一个示例类: 在模块类中: DepB类别: 据我所知,对于用< code>@Inject注释的变量,Google Guice会使用模块类来解决这些依赖关系。所以< code>DepA对象的注入方式是有意义的。 但是呢?我们如何能够在不指定任何位置的情况下注入DepB?

  • 这里提出的问题是:https://vaadin.com/forum/thread/18095407/how-to-create-a-grid-without-binder 然而,瓦丁的论坛关闭了,所以我想在这里继续。 关于Vaadin 14,任何关于实现动态变化列数网格的最佳方法的建议。使用列索引(1,2,3...)对我来说不是一个好选择。假设我有一个简单的Json文件(只有1个级别:key-va

  • 1,当我的字典树像这样时,会出现错误“@EnableSync注释元数据未注入” 2、但是当我的字典树喜欢这个时,错误就不会发生。 3、当我用application.xml连接Bean时,字典树喜欢第一段,但错误也没有发生。 所以我所确认的是@ComponentScan在没有应用程序的情况下连接Bean时的工作。xml?

  • 问题内容: 我从 JavaEE 6中 了解到,它是可选的。 因此,如果没有 web.xml ,如何告诉应用程序服务器使用Jersey作为JAX-RS规范的实现? 问题答案: 就如何在没有web.xml的情况下实现应用程序配置而言,@AlexNevidomsky的回答是正确的。您在子类上使用注释。 有关部署选项的更多信息,请参见JAX-RS规范-> 2.3发布-> 2.3.2Servlet。 或更常