Mastering Partial Updates in Spring Boot 3: @JsonMerge & @JsonSetter Explained
This article demonstrates how to implement elegant partial updates in Spring Boot 3 by combining @JsonMerge and @JsonSetter(nulls = Nulls.SKIP), addressing null‑value handling, reducing boilerplate code, and ensuring nested objects and maps are merged correctly.
1. Introduction
In RESTful API design, the PATCH method is used for partial updates, sending only the fields that need to change while leaving others untouched. Implementing partial updates in Spring Boot often raises the question of how to handle null values correctly.
The main challenge is distinguishing between a client‑sent null (intending to clear a field) and an omitted field (which should be ignored).
2. Practical Example
2.1 Prepare Environment
Environment: Spring Boot 3.4.2
public class User {
private String name;
private Integer age;
private Address address;
private Map<String, Object> extras;
}
public class Address {
private String province;
private String city;
private String county;
private String street;
}
@RestController
@RequestMapping("/merge/users")
public class MergeController {
private User user;
public MergeController() {
User user = new User();
user.setName("张三");
user.setAge(30);
Address address = new Address();
address.setProvince("新疆维吾尔自治区");
address.setCity("乌鲁木齐市");
address.setCounty("天山区");
address.setStreet("卫星路");
user.setAddress(address);
user.setExtras(new HashMap<>(Map.of("hobby","coding","gender","female")));
this.user = user;
}
@GetMapping
public ResponseEntity<User> getUser() {
return ResponseEntity.ok(this.user);
}
}Access GET /merge/users to retrieve the initial object.
2.2 Traditional Update Method
Using @PutMapping and manually checking each field for null leads to verbose and error‑prone code:
@PutMapping
public ResponseEntity<User> updateUser(@RequestBody User updatedUser) {
if (updatedUser.getName() != null) {
user.setName(updatedUser.getName());
}
if (updatedUser.getAge() != null) {
user.setAge(updatedUser.getAge());
}
// other fields...
return ResponseEntity.ok(user);
}Problems:
Lengthy code and easy mistakes, especially with nested objects.
High maintenance when the model changes.
Ambiguous null semantics – a null cannot be used to explicitly clear a field.
Violates DRY principle.
2.3 Using @JsonMerge
Annotating fields with @JsonMerge allows Jackson to merge incoming JSON into the existing object:
public class User {
@JsonMerge
private Address address;
@JsonMerge
private Map<String, Object> extras;
}Controller method:
private final ObjectMapper objectMapper;
private User user;
@PutMapping
public ResponseEntity<User> updateUser(@RequestBody User updatedUser) throws Exception {
User mergedUser = objectMapper.readerForUpdating(this.user)
.readValue(objectMapper.writeValueAsString(updatedUser));
this.user = mergedUser;
return ResponseEntity.ok(this.user);
}Access PUT /merge/users to apply the merge.
2.4 Using @JsonSetter + @JsonMerge
Adding @JsonSetter(nulls = Nulls.SKIP) to primitive fields tells Jackson to ignore null values during merge, while @JsonMerge still merges collections and nested objects:
public class User {
@JsonSetter(nulls = Nulls.SKIP)
private String name;
@JsonSetter(nulls = Nulls.SKIP)
private Integer age;
@JsonMerge
private Address address;
@JsonMerge
private Map<String, Object> extras;
}
public class Address {
@JsonSetter(nulls = Nulls.SKIP)
private String province;
@JsonSetter(nulls = Nulls.SKIP)
private String city;
@JsonSetter(nulls = Nulls.SKIP)
private String county;
@JsonSetter(nulls = Nulls.SKIP)
private String street;
}After updating via PUT /merge/users , null values are skipped, preventing unwanted overwrites.
Conclusion
Combining @JsonMerge with @JsonSetter(nulls = Nulls.SKIP) provides an elegant solution for partial updates in Spring Boot: nested objects and maps are merged, while nulls are ignored unless explicitly desired. Remember that without @JsonMerge on a field, a null will overwrite the existing value.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
