Adding Custom Serializers and Deserializers to Jackson’s ObjectMapper

有时候,Spring Data REST ObjectMapper(已专门配置为使用可将域对象转换为链接然后再返回的可理解序列化程序)的行为可能无法正确处理您的域模型。您可以用多种方式来构建数据,从而发现自己无法将域模型正确转换为 JSON。而且,在这些情况下,以通用方式支持复杂的域模型有时也不切实际。有时,根据复杂性,甚至无法提供一个通用的解决方案。

Sometimes, the behavior of the Spring Data REST ObjectMapper (which has been specially configured to use intelligent serializers that can turn domain objects into links and back again) may not handle your domain model correctly. You can structure your data in so many ways that you may find your own domain model does not correctly translate to JSON. It is also sometimes not practical in these cases to support a complex domain model in a generic way. Sometimes, depending on the complexity, it is not even possible to offer a generic solution.

为了适应大多数用例,Spring Data REST 会尝试正确渲染对象图。它会尝试将非托管 Bean 序列化为常规 POJO,并尝试在需要时创建到托管 Bean 的链接。但是,如果您的域模型无法轻松地用于读取或写入纯 JSON,您可能希望使用您自己的自定义类型映射和(反)序列化程序来配置 Jackson 的 ObjectMapper

To accommodate the largest percentage of the use cases, Spring Data REST tries to render your object graph correctly. It tries to serialize unmanaged beans as normal POJOs, and tries to create links to managed beans where necessary. However, if your domain model does not easily lend itself to reading or writing plain JSON, you may want to configure Jackson’s ObjectMapper with your own custom type mappings and (de)serializers.

Abstract Class Registration

您可能需要挂钩的一个键配置点是,在域模型中使用抽象类(或接口)时。默认情况下,Jackson 不知道为一个接口创建什么实现。请考虑以下示例:

One key configuration point you might need to hook into is when you use an abstract class (or an interface) in your domain model. Jackson does not, by default, know what implementation to create for an interface. Consider the following example:

@Entity
public class MyEntity {

  @OneToMany
  private List<MyInterface> interfaces;
}

在默认配置中,当将新数据 POST 到导出程序时,Jackson不知道要实例化哪个类。您需要通过注释或通过使用 Module注册类型映射来告诉 Jackson。

In a default configuration, Jackson has no idea what class to instantiate when POSTing new data to the exporter. You need to tell Jackson either through an annotation or, more cleanly, by registering a type mapping by using a Module.

ApplicationContext 范围内声明的任何 模块 Bean 都将由导出程序选取并用其 ObjectMapper 注册。若要添加此特殊抽象类类型映射,您可以创建一个 Module Bean,并在 setupModule 方法中添加一个适当的 TypeResolver,如下所示:

Any Module bean declared within the scope of your ApplicationContext is picked up by the exporter and registered with its ObjectMapper. To add this special abstract class type mapping, you can create a Module bean and, in the setupModule method, add an appropriate TypeResolver, as follows:

public class MyCustomModule extends SimpleModule {

  private MyCustomModule() {
    super("MyCustomModule", new Version(1, 0, 0, "SNAPSHOT"));
  }

  @Override
  public void setupModule(SetupContext context) {
    context.addAbstractTypeResolver(
      new SimpleAbstractTypeResolver().addMapping(MyInterface.class,
        MyInterfaceImpl.class));
  }
}

一旦您在 Module 中访问了 SetupContext 对象,您就可以执行各种很酷的操作来配置 Jackon 的 JSON 映射。您可以阅读有关如何 Modules work on Jackson’s wiki 的更多信息。

Once you have access to the SetupContext object in your Module, you can do all sorts of cool things to configure Jackon’s JSON mapping. You can read more about how Modules work on Jackson’s wiki.

Adding Custom Serializers for Domain Types

如果您想以特别方式序列化或反序列化域类型,可以使用 Jackson 的 ObjectMapper 注册您自己的实现。然后,Spring Data REST 导出程序会透明地正确处理那些域对象。

If you want to serialize or deserialize a domain type in a special way, you can register your own implementations with Jackson’s ObjectMapper. Then the Spring Data REST exporter transparently handles those domain objects correctly.

若要从 setupModule 方法实现添加序列化程序,您可以执行类似以下的操作:

To add serializers from your setupModule method implementation, you can do something like the following:

public class MyCustomModule extends SimpleModule {

  …

  @Override
  public void setupModule(SetupContext context) {

    SimpleSerializers serializers = new SimpleSerializers();
    SimpleDeserializers deserializers = new SimpleDeserializers();

    serializers.addSerializer(MyEntity.class, new MyEntitySerializer());
    deserializers.addDeserializer(MyEntity.class, new MyEntityDeserializer());

    context.addSerializers(serializers);
    context.addDeserializers(deserializers);
  }
}

承蒙前一示例中显示的自定义模块,当 Spring Data REST 试图涵盖的 80% 一般用例条件太复杂时,Spring Data REST 正确处理你的域对象。

Thanks to the custom module shown in the preceding example, Spring Data REST correctly handles your domain objects when they are too complex for the 80% generic use case that Spring Data REST tries to cover.