You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Lombok与Jackson创建可序列化不可变类的最优实现方案问询

创建支持Jackson序列化/反序列化的不可变类最优方案

嘿,针对你想要创建不可变类(private final字段、无Setter),同时支持Jackson序列化/反序列化、可读性强、样板代码少的需求,我整理了几个靠谱的方案,顺便帮你排查下之前踩的坑~

一、最省心的Lombok+Jackson组合方案

这应该是最符合你需求的方式,用Lombok减少重复代码,配合Jackson注解搞定序列化/反序列化:

1. 基础版(兼容所有Jackson版本)

你之前的问题核心是漏了Getter注解,以及@JsonCreator的配置不到位。直接用下面的注解组合就能解决:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.ToString;
import lombok.EqualsAndHashCode;

@Getter // 必须加!Jackson序列化需要Getter读取字段值
@ToString
@EqualsAndHashCode
public class ImmutableUser {
    private final String username;
    private final int age;
    private final String email;

    // @JsonCreator告诉Jackson用这个构造器反序列化
    @JsonCreator
    public ImmutableUser(
            // @JsonProperty映射JSON字段和构造器参数
            @JsonProperty("username") String username,
            @JsonProperty("age") int age,
            @JsonProperty("email") String email) {
        this.username = username;
        this.age = age;
        this.email = email;
    }
}

2. 进阶简化版(用Lombok自动生成构造器)

不想手动写构造器?可以用@AllArgsConstructor配合@JsonCreator,记得一定要加@Getter:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.AllArgsConstructor;
import lombok.ToString;
import lombok.EqualsAndHashCode;

@Getter
@ToString
@EqualsAndHashCode
// 让Lombok生成全参构造器,并给构造器加上@JsonCreator
@AllArgsConstructor(onConstructor = @__(@JsonCreator(mode = JsonCreator.Mode.PROPERTIES)))
public class ImmutableUser {
    // @JsonProperty标注字段,同时映射序列化/反序列化的字段名
    @JsonProperty("username")
    private final String username;
    @JsonProperty("age")
    private final int age;
    @JsonProperty("email")
    private final String email;
}

这里指定JsonCreator.Mode.PROPERTIES是为了让Jackson按属性名匹配参数,避免依赖额外模块,兼容性更好。

二、帮你分析之前的问题

1. @Data(onConstructor = @__(@JsonCreator))编译失败的原因

@Data包含@RequiredArgsConstructor,只会给final字段生成构造器,但旧版本Lombok不支持直接在@Data上通过onConstructor添加@JsonCreator。另外,即使编译通过,生成的构造器参数没有@JsonProperty,Jackson也没法正确映射JSON字段,一样会出问题。

2. @AllArgsConstructor(onConstructor = @__(@JsonCreator))抛出序列化异常的原因

@AllArgsConstructor只生成全参构造器,不会生成Getter方法!Jackson序列化时默认需要通过Getter读取字段值,没有Getter自然会抛出InvalidDefinitionException: No serializer found...,加上@Getter就解决了。

三、更进一步:用Jackson参数名称模块省掉@JsonProperty

如果你的项目用Java 8+,可以引入Jackson的参数名称模块,彻底省去@JsonProperty的编写:

  1. 先加Maven依赖(版本和你的Jackson保持一致):
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-parameter-names</artifactId>
    <version>2.15.2</version> <!-- 换成你的Jackson版本 -->
</dependency>
  1. 给ObjectMapper注册这个模块:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());
  1. 简化到极致的不可变类:
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;
import lombok.AllArgsConstructor;
import lombok.ToString;
import lombok.EqualsAndHashCode;

@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor(onConstructor = @__(@JsonCreator))
public class ImmutableUser {
    private final String username;
    private final int age;
    private final String email;
}

这个模块会利用Java 8的参数名称反射功能,让Jackson自动匹配JSON字段和构造器参数名,代码超干净!

四、纯Jackson方案(不用Lombok)

如果不想依赖Lombok,纯Jackson注解也能实现,只是样板代码会多一点:

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

public class ImmutableUser {
    private final String username;
    private final int age;
    private final String email;

    @JsonCreator
    public ImmutableUser(
            @JsonProperty("username") String username,
            @JsonProperty("age") int age,
            @JsonProperty("email") String email) {
        this.username = username;
        this.age = age;
        this.email = email;
    }

    // Jackson序列化需要这些Getter
    @JsonGetter("username")
    public String getUsername() {
        return username;
    }

    @JsonGetter("age")
    public int getAge() {
        return age;
    }

    @JsonGetter("email")
    public String getEmail() {
        return email;
    }

    // 可选:重写toString、equals、hashCode提升可读性
    @Override
    public String toString() {
        return "ImmutableUser{" +
                "username='" + username + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

内容的提问来源于stack exchange,提问作者Christian Neverdal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:29:07