docs(blogs): add Jackson JSON flattening guide
- Add @JsonUnwrapped and @JsonAnyGetter usage examples with code - Include comparison table for choosing between annotations - Sync content across zh-hans and en-gb versions
This commit is contained in:
2 files changed
+144
No files matched your search
@@ -207,4 +207,75 @@ Specification<User> spec = (root, query, cb) -> {
|
||||
Page<User> page = userRepository.findAll(spec, pageable);
|
||||
```
|
||||
|
||||
## Flattening Objects or Maps into JSON with Jackson
|
||||
|
||||
When serialising to JSON, you sometimes need to "flatten" a nested object's properties into the parent JSON rather than having them appear as a nested field. Jackson provides two annotations for handling objects and `Map` flattening separately.
|
||||
|
||||
### `@JsonUnwrapped` — flattening objects with a known structure
|
||||
|
||||
`@JsonUnwrapped` expands the properties of a nested object directly into the parent JSON:
|
||||
|
||||
```java
|
||||
public class Address {
|
||||
private String street;
|
||||
private String city;
|
||||
// getters and setters
|
||||
}
|
||||
|
||||
public class User {
|
||||
private String name;
|
||||
|
||||
@JsonUnwrapped
|
||||
private Address address;
|
||||
// getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
Serialised output:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "John Doe",
|
||||
"street": "Oxford Street",
|
||||
"city": "London"
|
||||
}
|
||||
```
|
||||
|
||||
Without `@JsonUnwrapped`, `address` would appear as a nested JSON object: `"address": { "street": "...", "city": "..." }`.
|
||||
|
||||
### `@JsonAnyGetter` — flattening a Map with dynamic keys
|
||||
|
||||
`@JsonAnyGetter` flattens a `Map`'s key-value pairs directly into the parent JSON, ideal for dynamic or open-ended fields:
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String name;
|
||||
|
||||
private Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
// other getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
With `attributes` containing `{"colour": "red", "size": "XL"}`, the serialised output is:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Example Product",
|
||||
"colour": "red",
|
||||
"size": "XL"
|
||||
}
|
||||
```
|
||||
|
||||
Note that `@JsonAnyGetter` must be placed on the **getter method**, not the field itself. You will also need `@JsonAnySetter` to support deserialisation.
|
||||
|
||||
### How to choose
|
||||
|
||||
| Scenario | Annotation |
|
||||
|-------------------------------------------------------|--------------------|
|
||||
| Flatten nested objects with fixed fields (e.g. address, config) | `@JsonUnwrapped` |
|
||||
| Flatten dynamic key-value pairs with unknown keys | `@JsonAnyGetter` |
|
||||
@@ -201,3 +201,76 @@ Specification<User> spec = (root, query, cb) -> {
|
||||
|
||||
Page<User> page = userRepository.findAll(spec, pageable);
|
||||
```
|
||||
|
||||
## 使用 Jackson 将对象或 Map 平铺到 JSON 中
|
||||
|
||||
在序列化 JSON 时,有时需要将嵌套对象的属性"平铺"到父级 JSON 中,而不是作为一个嵌套字段出现。Jackson 提供了两个注解来分别处理对象和 `Map` 的平铺场景。
|
||||
|
||||
### `@JsonUnwrapped` — 平铺已知结构的对象
|
||||
|
||||
`@JsonUnwrapped` 会将一个嵌套对象的属性直接展开到父级 JSON 中:
|
||||
|
||||
```java
|
||||
public class Address {
|
||||
private String street;
|
||||
private String city;
|
||||
// getters and setters
|
||||
}
|
||||
|
||||
public class User {
|
||||
private String name;
|
||||
|
||||
@JsonUnwrapped
|
||||
private Address address;
|
||||
// getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
序列化结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "陳大文",
|
||||
"street": "彌敦道",
|
||||
"city": "香港"
|
||||
}
|
||||
```
|
||||
|
||||
如果不使用 `@JsonUnwrapped`,`address` 会作为一个嵌套 JSON 对象出现:`"address": { "street": "...", "city": "..." }`。
|
||||
|
||||
### `@JsonAnyGetter` — 平铺键值不固定的 Map
|
||||
|
||||
`@JsonAnyGetter` 可以将 `Map` 中的键值对直接平铺到父级 JSON 中,适合 key 不固定或动态扩展的场景:
|
||||
|
||||
```java
|
||||
public class Product {
|
||||
private String name;
|
||||
|
||||
private Map<String, Object> attributes = new HashMap<>();
|
||||
|
||||
@JsonAnyGetter
|
||||
public Map<String, Object> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
// other getters and setters
|
||||
}
|
||||
```
|
||||
|
||||
当 `attributes` 包含 `{"colour": "red", "size": "XL"}` 时,序列化结果:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Example Product",
|
||||
"colour": "red",
|
||||
"size": "XL"
|
||||
}
|
||||
```
|
||||
|
||||
注意 `@JsonAnyGetter` 需要加在 **getter 方法**上,而不是字段上;同时需要搭配 `@JsonAnySetter` 来支持反序列化。
|
||||
|
||||
### 如何选择
|
||||
|
||||
| 场景 | 注解 |
|
||||
|----------------------------------------|--------------------|
|
||||
| 平铺字段固定的嵌套对象(如地址、配置) | `@JsonUnwrapped` |
|
||||
| 平铺 key 不固定的动态键值对 | `@JsonAnyGetter` |
|
||||
Reference in new issue
Block a user