在 Jackson 的 ObjectMapper 中新增自訂序列化器與反序列化器

有時候,Spring Data REST 的 ObjectMapper 行為 (已特別設定為使用智慧型序列化器,可將網域物件轉換為連結並再次轉換回來) 可能無法正確處理您的網域模型。您可以使用多種方式來架構您的資料,因此您可能會發現自己的網域模型無法正確轉換為 JSON。在這些情況下,以通用方式支援複雜的網域模型有時也不切實際。有時,根據複雜程度,甚至不可能提供通用的解決方案。

為了容納最大比例的使用案例,Spring Data REST 嘗試正確呈現您的物件圖形。它嘗試將非受管 bean 序列化為普通的 POJO,並在必要時嘗試建立受管 bean 的連結。但是,如果您的網域模型不容易進行純 JSON 的讀取或寫入,您可能需要使用自己的自訂類型映射和 (反)序列化器來設定 Jackson 的 ObjectMapper

抽象類別註冊

您可能需要介入的一個關鍵設定點是當您在網域模型中使用抽象類別 (或介面) 時。預設情況下,Jackson 不知道要為介面建立哪個實作。請考慮以下範例

@Entity
public class MyEntity {

  @OneToMany
  private List<MyInterface> interfaces;
}

在預設設定中,當將新資料 POST 到匯出器時,Jackson 不知道要實例化哪個類別。您需要透過註解或更簡潔的方式,使用 Module 註冊類型映射來告訴 Jackson。

在您的 ApplicationContext 範圍內宣告的任何 Module bean 都會被匯出器選取,並註冊到其 ObjectMapper 中。若要新增此特殊的抽象類別類型映射,您可以建立 Module bean,並在 setupModule 方法中新增適當的 TypeResolver,如下所示

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 物件,您就可以執行各種很棒的操作來設定 Jackson 的 JSON 映射。您可以在 Jackson 的 Wiki 上閱讀更多關於 Modules 如何運作的資訊。

為網域類型新增自訂序列化器

如果您想要以特殊方式序列化或反序列化網域類型,您可以向 Jackson 的 ObjectMapper 註冊您自己的實作。然後 Spring Data REST 匯出器就會以透明方式正確處理這些網域物件。

若要從您的 setupModule 方法實作中新增序列化器,您可以執行類似以下的操作

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 可以正確處理它們。