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

使用@Jacksonized @Builder @Value注解序列化POJO产生空JSON问题排查

Lombok+Jackson序列化Payload为空问题解决方案

版本信息

  • lombok: 1.18.20
  • spring-boot: 2.5.4

lombok.config配置(IntelliJ默认生成)

# add @lombok.Generated annotation to all Lombok generated methods
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true

相关代码

Payload.java

@Jacksonized @Builder @Value
public class Payload<T> {
    @Getter(AccessLevel.NONE)
    private T content;

    /**
     * @return payload content
     */
    public T get() {
        return content;
    }
}

ApiRequest.java

@Jacksonized @Builder @Value
public class ApiRequest<T> {
    private Date timestamp;
    private Payload<T> payload;
}

Metadata.java

@Jacksonized @Builder(toBuilder = true) @Value
public class Metadata {
    private String element;
    private String threshold;
    private String groupType;
    private String groupId;
    private String groupName;
    private String groupPath;
    private Instant from;
    private Instant to;
}

MyRestController.java

@Slf4j
@Validated
@RestController
@RequestMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
@RequestScope
public class MyRestController {
    @RequestMapping(
            path = "/process",
            method = RequestMethod.POST,
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public ApiResponse process(@RequestBody ApiRequest<List<Metadata>> apiRequest) {
        log.info("Received request: " + apiRequest);
        return null; // 暂时忽略返回
    }

    /*public ApiResponse process(@RequestBody String json) {
        log.info("Received request: " + json);
        return null; // 暂时忽略返回
    }*/
}

TestClass.java

public class TestClass {
    public static void main(String[] args) throws Exception {
        String fromStr = "2021-09-05T00:00:00Z";
        String toStr = "2021-09-11T23:59:59Z";
        Instant from = Instant.parse(fromStr);
        Instant to = Instant.parse(toStr);
        String groupName = "SomeGroupName";
        String groupPath = "SomeGroupPath";

        List<Metadata> metadataList = new ArrayList<>();
        metadataList.add(Metadata.builder().element("e1").threshold("48").groupName(groupName).groupPath(groupPath).from(from).to(to).build());
        metadataList.add(Metadata.builder().element("e2").threshold("35").groupName(groupName).groupPath(groupPath).from(from).to(to).build());
        metadataList.add(Metadata.builder().element("e3").threshold("90").groupName(groupName).groupPath(groupPath).from(from).to(to).build());

        Payload<List<Metadata>> payload = Payload.<List<Metadata>>builder().content(metadataList).build();
        ApiRequest<List<Metadata>> apiRequest = ApiRequest.<List<Metadata>>builder().payload(payload).build();

        RestTemplate rt = new RestTemplate();
        final String baseUrl = "http://localhost:8080/test/process";
        URI uri = new URI(baseUrl);
        ResponseEntity<ApiResponse> response = rt.postForEntity(uri, apiRequest, ApiResponse.class);
        ApiResponse r = response.getBody();
    }
}

问题现象

运行代码时,MyRestController收到的apiRequest为null,即使取消控制器中注释的接收原始JSON字符串的方法,也能看到payload字段为空,实际打印的请求内容如下:

Received request: {"timestamp":null,"payload":{}}

疑问

  1. 本次序列化失败的错误点在哪里?
  2. 序列化正常后,ApiResponse反序列化是否需要特殊处理?
    要求优先通过@Jacksonized注解实现功能。

已验证解决方案

问题出在Payload类的定义上,修改代码即可解决:

@Jacksonized @Builder @Value
public class Payload<T> {
    @Getter(AccessLevel.NONE)
    private T content;

    /**
     * @return payload content
     */
    @JsonProperty("content") // 新增该注解指定Jackson使用此getter获取content字段
    public T get() {
        return content;
    }
}

原因说明

通过@Getter(AccessLevel.NONE)关闭了Lombok为content字段自动生成的标准JavaBean getter方法getContent()后,自定义的get()方法不符合Jackson默认的getter命名规则,Jackson无法将该方法和content字段关联,导致序列化时读取不到content的值,最终payload序列化结果为空。添加@JsonProperty("content")后会显式告知Jackson该方法对应content字段的读方法,就能正常完成序列化和反序列化流程。

ApiResponse处理说明

只要ApiResponse类也使用@Jacksonized + @Builder + @Value的组合注解,且内部没有类似Payload这种自定义的不符合命名规范的getter/setter,就不需要额外做特殊处理。@Jacksonized注解已经自动完成了Jackson和Lombok Builder的适配,Spring Boot 2.5.4默认的Jackson配置完全兼容该注解,直接使用即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:15:08