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

Jackson序列化字段名不匹配:实体类转请求体时字段名未按预期转换

问题分析与解决方案

看起来你遇到的核心问题是Jackson序列化配置错误,导致JSON输出的字段名和根节点不符合预期。我帮你拆解下问题点,然后给出具体的修复方案:

问题根源

  1. 注解库混淆:你用了Gson的@SerializedName注解,但RestAssured默认使用Jackson进行JSON序列化,这个注解Jackson根本不认!
  2. XML注解无效于JSON:@JacksonXmlProperty只对XML序列化生效,JSON序列化完全不搭理它。
  3. 根节点未开启包裹:@JsonRootName注解默认不会生效,必须手动开启Jackson的根节点序列化配置。
  4. Feature类注解缺失:Feature里的集合字段也没配置正确的Jackson注解,导致输出格式不对。

修复步骤与代码调整

1. 修正ComputerInfo类的注解

替换Gson的@SerializedName为Jackson的@JsonProperty,同时保留XML相关注解(如果需要支持XML序列化的话):

import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;

@JsonRootName(value = "Laptop") 
@XmlRootElement(name = "Laptop")
public class ComputerInfo {
    @JsonProperty("BrandName")
    @JacksonXmlProperty(isAttribute = true, localName = "BrandName")
    private String brandName;
    
    @JsonProperty("Id")
    @JacksonXmlProperty(isAttribute = true, localName = "Id")
    private String id;
    
    @JsonProperty("LaptopName")
    @JacksonXmlProperty(isAttribute = true, localName = "LaptopName")
    private String laptopName;
    
    @JsonProperty("Features")
    @JacksonXmlProperty(localName = "Features")
    private Feature features;

    @JsonProperty("BrandName")
    @XmlElement(name = "BrandName")
    public String getBrandName() { return brandName; }
    
    @JsonProperty("Id")
    @XmlElement(name = "Id")
    public String getId() { return id; }
    
    @JsonProperty("LaptopName")
    @XmlElement(name = "LaptopName")
    public String getLaptopName() { return laptopName; }
    
    @JsonProperty("Features")
    @XmlElement(name = "Features")
    public Feature getFeatures() { return features; }

    // setter方法无需额外注解,Jackson自动识别
    public void setBrandName(String brandName) { this.brandName = brandName; }
    public void setId(String id) { this.id = id; }
    public void setLaptopName(String laptopName) { this.laptopName = laptopName; }
    public void setFeatures(Feature features) { this.features = features; }

    @Override
    public String toString() {
        return "ComputerInfo{" + "brandName='" + brandName + '\'' + ", id='" + id + '\'' + ", laptopName='" + laptopName + '\'' + ", features=" + features + '}';
    }
}

2. 修正Feature类的注解

给集合字段加上Jackson的@JsonProperty,指定JSON输出的字段名:

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import java.util.ArrayList;

public class Feature {
    @JsonProperty("Feature")
    @JacksonXmlProperty(localName = "Feature")
    private ArrayList<String> feature;

    @JsonProperty("Feature")
    public ArrayList<String> getFeature() { return feature; }

    public void setFeature(ArrayList<String> feature) { this.feature = feature; }
}

3. 配置RestAssured的Jackson ObjectMapper

开启根节点包裹功能,让@JsonRootName生效:

import io.restassured.RestAssured;
import io.restassured.config.ObjectMapperConfig;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.junit.Test;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.http.HttpStatus.SC_OK;

@Test
public void testPostWithObjectMapping() throws URISyntaxException {
    // 自定义Jackson配置,开启根节点序列化/反序列化
    RestAssured.config = RestAssured.config()
            .objectMapperConfig(new ObjectMapperConfig()
                    .jackson2ObjectMapperFactory((cls, charset) -> {
                        com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper();
                        mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
                        mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
                        return mapper;
                    }));

    URI uri = new URI("http://localhost:8080/laptop-bag/webapi/api/add");
    String id = new Random().nextInt(500) + "";
    ComputerInfo info = new ComputerInfo();
    info.setBrandName("Microsoft");
    info.setId(id);
    info.setLaptopName("Surface");
    Feature feature = new Feature();
    feature.setFeature(new ArrayList<>(Arrays.asList("8GB RAM", "1 TB Hard Drive")));
    info.setFeatures(feature);

    Response response = given().accept(ContentType.JSON)
            .log().body()
            .contentType(ContentType.JSON)
            .body(info)
            .post(uri);

    response.then()
            .assertThat()
            .statusCode(SC_OK)
            .body("Laptop.Id", equalTo(info.getId()));
}

关键说明

  • 注解选择:Jackson用@JsonProperty指定JSON字段名,Gson用@SerializedName,千万别搞混!
  • 根节点生效:WRAP_ROOT_VALUE配置是让@JsonRootName生效的关键,没有它,JSON输出只会是扁平化的字段,不会有外层的Laptop节点。
  • XML兼容:如果你同时需要支持XML和JSON序列化,保留@JacksonXmlProperty和@XmlElement即可,Jackson会自动区分两种格式的序列化规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:15:08