切換語言為:簡體
Jackson 如何反序列化不可變類

Jackson 如何反序列化不可變類

  • 爱糖宝
  • 2024-06-02
  • 2133
  • 0
  • 0

Jackson預設的反序列化策略需要無參構造器,並提供欄位setter函式。

如下ImmutableUser類屬性都被final修飾,只有全參構造器,沒有setter方法,它的例項一經建立就不可變。如何使用Jackson反序列化它呢?

public class ImmutableUser {

  private final String name;
  private final int age;
  private final String identityCard;

  public ImmutableUser(String name, int age, String identityCard) {
    this.name = name;
    this.age = age;
    this.identityCard = identityCard;
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }

  public String getIdentityCard() {
    return identityCard;
  }
}


或許你會寫下這樣的程式碼,結果發現一執行就報錯了:no Creators, like default constructor, exist.

@Test
public void readImmutableUser() throws JsonProcessingException {
  String userJson = "{"name":"Tom","age":23,"identityCard":"61012420000101012x"}";
  ObjectMapper mapper = new ObjectMapper();
  ImmutableUser user = mapper.readValue(userJson, ImmutableUser.class);
  System.out.println(MAPPER.writeValueAsString(user));
}


com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.learn.more.entiry.ImmutableUser (no Creators, like default constructor, exist): ......

一 使用Jackson註解

可以使用@JsonProperty更改反序列化策略。

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

// 與ImmutableUser的區別:使用@JsonProperty、@JsonCreator修飾全參構造器
public class ImmutableUser2 {

  private final String name;
  private final int age;
  private final String identityCard;

  @JsonCreator
  public ImmutableUser2(@JsonProperty("name") String name,
  @JsonProperty("age") int age, @JsonProperty("identityCard") String identityCard) {
    this.name = name;
    this.age = age;
    this.identityCard = identityCard;
  }

  public String getName() {
    return name;
  }

  public int getAge() {
    return age;
  }

  public String getIdentityCard() {
    return identityCard;
  }
}


還是上面的測試程式碼,這次發現執行成功了。

  Jackson 如何反序列化不可變類 

需注意,@JsonProperty的value必須填寫,且最好與Json串中欄位名一致。否則將導致下面的異常。

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Invalid type definition for type com.learn.more.entiry.ImmutableUser2: ..., annotations: ... has no property name (and is not Injectable): can not use as property-based Creator

二 使用jackson-module-parameter-names

如果ImmutableUser類來自jar包,我們無法修改原始碼來新增@JsonProperty、@JsonCreator註解。又該如何處理呢?

由官方維護的jackson-module-parameter-namesModule,正好可以實現無侵入的反序列化不可變類。引入依賴:

 <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
      <version>${jackson.version}</version>
</dependency>


向ObjectMapper註冊ParameterNamesModule,就可以執行成功了。

@Test
public void readImmutableUser() throws JsonProcessingException {
  String userJson = "{"name":"Tom","age":23,"identityCard":"61012420000101012x"}";
  ObjectMapper mapper = new ObjectMapper();
  mapper.registerModule(new ParameterNamesModule());
  ImmutableUser user = mapper.readValue(userJson, ImmutableUser.class);
  System.out.println(MAPPER.writeValueAsString(user));
}


Jackson 如何反序列化不可變類

三 使用Mixins機制

Jackson提供了mixins 機制,支援外掛式的序列化/反序列化策略宣告,從而避免對源數據結構的侵入性改變。我們反序列化第三方的不可變類時,可以使用該機制:

建立ImmutableUserMixin類,具有與ImmutableUser相似的構造器引數,使用 @JsonProperty宣告了引數對應的json欄位。

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

public class ImmutableUserMixin {

  @JsonCreator
  public ImmutableUserMixin(@JsonProperty("name") String name,
  @JsonProperty("age") int age, @JsonProperty("identityCard") String identityCard) {

  }
}


再建立一個自定義的JacksonMixinModule類,將ImmutableUser與ImmutableUserMixin對應關係,設定到SetupContext

import com.fasterxml.jackson.databind.module.SimpleModule;
import com.learn.more.entiry.ImmutableUser;
import com.learn.more.entiry.ImmutableUserMixin;

public class JacksonMixinModule extends SimpleModule {

  public JacksonMixinModule() {
    super(JacksonMixinModule.class.getName());
  }

  // 註冊所有使用Mixin機制的類
  @Override
  public void setupModule(SetupContext context) {
    context.setMixInAnnotations(ImmutableUser.class, ImmutableUserMixin.class);
    // ......
  }
}


向ObjectMapper註冊JacksonMixinModule類。那麼,在反序列化ImmutableUser時,將依據ImmutableUserMixin的構造器宣告來繫結屬性值。

@Test
public void readImmutableUserMixin() throws JsonProcessingException {
  String userJson = "{"name":"Tom","age":23,"identityCard":"61012420000101012x"}";
  ObjectMapper mapper = new ObjectMapper();
  mapper.registerModule(new JacksonMixinModule());
  ImmutableUser user = mapper.readValue(userJson, ImmutableUser.class);
  System.out.println(MAPPER.writeValueAsString(user));
}


可以成功反序列化

  Jackson 如何反序列化不可變類


0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.