Jackson反序列化不可变类

程序浅谈 后端 2024-11-13

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; } }

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

Jackson反序列化不可变类

三 使用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)); }

可以成功反序列化Jackson反序列化不可变类

转载来源:https://juejin.cn/post/7375072185209438220

Apipost 私有化火热进行中

评论