Jackson序列化字段名不匹配:实体类转请求体时字段名未按预期转换
问题分析与解决方案
看起来你遇到的核心问题是Jackson序列化配置错误,导致JSON输出的字段名和根节点不符合预期。我帮你拆解下问题点,然后给出具体的修复方案:
问题根源
- 注解库混淆:你用了Gson的
@SerializedName注解,但RestAssured默认使用Jackson进行JSON序列化,这个注解Jackson根本不认! - XML注解无效于JSON:
@JacksonXmlProperty只对XML序列化生效,JSON序列化完全不搭理它。 - 根节点未开启包裹:
@JsonRootName注解默认不会生效,必须手动开启Jackson的根节点序列化配置。 - 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
相关产品推荐
相关产品推荐

