Keywords: Spring Boot | @RequestBody | JSON Mapping | Jackson | Property Naming
Abstract: This article provides an in-depth analysis of common field mapping issues when using the @RequestBody annotation to process JSON requests in Spring Boot. Through a practical case study, it explains the mapping rules between JSON property names and Java Bean property names, with particular emphasis on case sensitivity. Starting from Spring's underlying data binding mechanism and combining with Jackson library's default behavior, the article offers multiple solutions including adjusting JSON property naming, using @JsonProperty annotation, and configuring ObjectMapper. It also discusses common error scenarios and debugging techniques to help developers fully understand and resolve the issue of @RequestBody receiving null values.
Problem Background and Phenomenon Description
In Spring Boot development of RESTful APIs, using the @RequestBody annotation to automatically bind JSON data from HTTP request bodies to Java objects is a common practice. However, developers frequently encounter a typical issue: when the JSON data sent by the client appears completely correct, the object properties received on the server side are all null. This article will analyze the root cause of this problem through a specific case study and provide systematic solutions.
Case Analysis: Policy Object Reception Issue
Consider the following Spring Boot controller code:
@RestController
public class Add_Policy {
@RequestMapping(value = "/Add_Policy",
consumes = MediaType.APPLICATION_JSON_VALUE,
method = RequestMethod.POST)
public Policy GetIPCountry(@RequestBody Policy policy) {
System.out.println("Check value: " + policy.getPolicyNumber());
return policy;
}
}
The corresponding Policy class is defined as follows:
public class Policy {
private String PolicyNumber;
private String Type;
private String Tenture;
private String SDate;
private String HName;
private String Age;
// Standard getter and setter methods
public String getPolicyNumber() {
return PolicyNumber;
}
public void setPolicyNumber(String policyNumber) {
PolicyNumber = policyNumber;
}
// Other getter and setter methods
}
The JSON data sent by the client is:
{
"PolicyNumber": "123",
"Type": "Test",
"Tenture": "10",
"SDate": "10-July-2016",
"HName": "Test User",
"Age": "10"
}
Despite correctly setting Content-Type: application/json in the request headers, the output of policy.getPolicyNumber() is null.
Root Cause Analysis
The Spring framework uses the Jackson library by default for JSON serialization and deserialization. When mapping JSON properties to Java object properties, Jackson follows specific naming conversion rules. By default, Jackson uses Java Bean naming conventions, inferring corresponding JSON property names from the getter and setter method names.
For the PolicyNumber property in the Policy class, its getter method is getPolicyNumber() and setter method is setPolicyNumber(). According to Java Bean specifications, Jackson removes the "get" or "set" prefix from the method name and converts the first character of the remaining part to lowercase, thus inferring that the corresponding JSON property name should be policyNumber.
However, the JSON sent by the client uses PolicyNumber (first letter uppercase), which doesn't match what Jackson expects (policyNumber with first letter lowercase), causing property mapping to fail and resulting in all property values being null.
Solutions
Solution 1: Adjust JSON Property Naming (Recommended)
Change JSON property names to lowercase first letter format:
{
"policyNumber": "123",
"type": "Test",
"tenture": "10",
"sDate": "10-July-2016",
"hName": "Test User",
"age": "10"
}
This solution best conforms to Java Bean specifications and Jackson's default behavior, ensuring proper property mapping.
Solution 2: Use @JsonProperty Annotation
Add @JsonProperty annotation to the Policy class properties or getter/setter methods to explicitly specify JSON property names:
public class Policy {
@JsonProperty("PolicyNumber")
private String PolicyNumber;
@JsonProperty("Type")
private String Type;
// Other properties similarly
// Or annotate on setter method
@JsonProperty("PolicyNumber")
public void setPolicyNumber(String policyNumber) {
this.PolicyNumber = policyNumber;
}
}
This approach allows maintaining the original JSON format while explicitly declaring mapping relationships through annotations.
Solution 3: Configure ObjectMapper
Customize ObjectMapper configuration to change Jackson's default naming strategy:
@Configuration
public class JacksonConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
// Use property names as JSON property names without case conversion
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
return mapper;
}
}
Alternatively, use other naming strategies like PropertyNamingStrategy.SNAKE_CASE, depending on project requirements.
Solution 4: Use @JsonNaming Annotation
Specify naming strategy at class level:
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class Policy {
// Class definition
}
This method uniformly specifies naming rules for the entire class.
Other Considerations
1. Correct @RequestBody Import
Ensure importing the correct @RequestBody annotation:
import org.springframework.web.bind.annotation.RequestBody; // Correct
// Avoid incorrectly importing同名 annotations from other packages
// import io.swagger.v3.oas.annotations.parameters.RequestBody; // Incorrect
2. Lombok Impact
When using Lombok to generate getter and setter methods, pay attention to Lombok's default naming approach. You can adjust naming behavior through the value parameter of @Getter and @Setter annotations or using the @Accessors annotation.
3. Debugging Techniques
When encountering property mapping issues, consider these debugging measures:
- Add
@RequestBody String rawJsonparameter to controller methods to first receive raw JSON strings for verification - Enable Spring Boot debug logging:
logging.level.org.springframework.web=DEBUG - Use Jackson's
@JsonAnySetterannotation to capture all unmapped properties - Enable
FAIL_ON_UNKNOWN_PROPERTIESin ObjectMapper to detect unknown properties
Best Practice Recommendations
- Maintain Naming Consistency: Use a unified naming convention throughout the project, preferably camelCase
- Explicitly Declare Mapping Relationships: For important DTO objects, use
@JsonPropertyannotation to explicitly specify JSON property names - Write Unit Tests: Create unit tests for serialization and deserialization of important API endpoints
- Document APIs: Use tools like Swagger/OpenAPI to generate API documentation, clearly describing request and response data structures
- Consider Version Compatibility: When APIs need backward compatibility, carefully modify property names or provide multiple version mapping support
Conclusion
The issue of @RequestBody receiving null values in Spring Boot typically stems from mismatched mapping between JSON property names and Java Bean property names. Understanding Jackson's default naming conversion rules is key to solving such problems. By adjusting JSON property naming, using annotations to explicitly declare mapping relationships, or configuring ObjectMapper's naming strategy, various mapping issues can be flexibly resolved. In practical development, establishing unified naming conventions combined with appropriate testing and documentation is recommended to ensure API stability and maintainability.