diff --git a/docs/en-gb/blogs/java-development-cheatsheet.md b/docs/en-gb/blogs/java-development-cheatsheet.md index 949454d..89868c6 100644 --- a/docs/en-gb/blogs/java-development-cheatsheet.md +++ b/docs/en-gb/blogs/java-development-cheatsheet.md @@ -207,4 +207,75 @@ Specification spec = (root, query, cb) -> { Page 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 attributes = new HashMap<>(); + + @JsonAnyGetter + public Map 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` | \ No newline at end of file diff --git a/docs/zh-hans/blogs/java-development-cheatsheet.md b/docs/zh-hans/blogs/java-development-cheatsheet.md index f487da7..bba4c83 100644 --- a/docs/zh-hans/blogs/java-development-cheatsheet.md +++ b/docs/zh-hans/blogs/java-development-cheatsheet.md @@ -201,3 +201,76 @@ Specification spec = (root, query, cb) -> { Page 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 attributes = new HashMap<>(); + + @JsonAnyGetter + public Map 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` |