Jackson反序列化不可变类

Jackson默认的反序列化策略需要无参构造器,并提供字段setter函数。

如下ImmutableUser类属性都被final修饰,只有全参构造器,没有setter方法,它的实例一经创建就不可变。如何使用Jackson反序列化它呢?

java 复制代码
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.

java 复制代码
@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更改反序列化策略。

java 复制代码
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;
  }
}

还是上面的测试代码,这次发现执行成功了。 需注意,@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,正好可以实现无侵入的反序列化不可变类。引入依赖:

xml 复制代码
 <dependency>
      <groupId>com.fasterxml.jackson.module</groupId>
      <artifactId>jackson-module-parameter-names</artifactId>
      <version>${jackson.version}</version>
</dependency>

向ObjectMapper注册ParameterNamesModule,就可以执行成功了。

java 复制代码
@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));
}

三 使用Mixins机制

Jackson提供了mixins 机制,支持外挂式的序列化/反序列化策略声明,从而避免对源数据结构的侵入性改变。我们反序列化第三方的不可变类时,可以使用该机制:

创建ImmutableUserMixin类,具有与ImmutableUser相似的构造器参数,使用 @JsonProperty声明了参数对应的json字段。

java 复制代码
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

java 复制代码
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的构造器声明来绑定属性值。

java 复制代码
@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));
}

可以成功反序列化

相关推荐
❥ღ Komo·2 小时前
K8s服务发现与DNS解析全解析
java·开发语言
g***B7384 小时前
Java 工程复杂性的真正来源:从语言设计到现代架构的全链路解析
java·人工智能·架构
期待のcode6 小时前
MyBatisX插件
java·数据库·后端·mybatis·springboot
醇氧8 小时前
【Windows】优雅启动:解析一个 Java 服务的后台启动脚本
java·开发语言·windows
sunxunyong8 小时前
doris运维命令
java·运维·数据库
菜鸟起航ing8 小时前
Spring AI 全方位指南:从基础入门到高级实战
java·人工智能·spring
未来魔导9 小时前
go语言中json操作总结
数据分析·go·json
古城小栈9 小时前
Docker 多阶段构建:Go_Java 镜像瘦身运动
java·docker·golang
华仔啊9 小时前
这 10 个 MySQL 高级用法,让你的代码又快又好看
后端·mysql
MapGIS技术支持9 小时前
MapGIS Objects Java计算一个三维点到平面的距离
java·开发语言·平面·制图·mapgis