如何使用Jackson将嵌套POJO/JSON自动转为指定格式Map<String,String>
基于Jackson的嵌套对象转表单Map实现方案
完全可以直接借助Jackson完成转换,无需引入额外依赖,自动适配@JsonProperty配置的字段名,生成符合multipart/form-data提交要求的扁平化键值对。
实现思路
先将POJO对象或JSON字符串解析为Jackson的JsonNode树形结构,递归遍历所有节点:
- 遇到嵌套对象节点时,按
父键[子字段名]的规则拼接键前缀,继续向下遍历 - 遇到字符串、数字、布尔等非嵌套的叶子节点时,直接将拼接好的完整键和节点转成的字符串值存入结果Map
由于Jackson在序列化、转树结构时会默认读取@JsonProperty等注解配置,整个过程不需要手动做字段名映射。
可直接使用的工具代码
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class FormFlatMapUtil { // 全局复用ObjectMapper,避免重复创建开销 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); /** * 从POJO对象直接转换为表单格式Map * @param pojo 待转换的嵌套POJO对象 * @return 扁平化的表单键值对Map */ public static Map<String, String> pojoToFormMap(Object pojo) throws IllegalArgumentException { JsonNode rootNode = OBJECT_MAPPER.valueToTree(pojo); Map<String, String> result = new HashMap<>(); traverseNode(rootNode, "", result); return result; } /** * 从已序列化的JSON字符串转换为表单格式Map * @param jsonStr 嵌套结构JSON字符串 * @return 扁平化的表单键值对Map */ public static Map<String, String> jsonToFormMap(String jsonStr) throws IllegalArgumentException { try { JsonNode rootNode = OBJECT_MAPPER.readTree(jsonStr); Map<String, String> result = new HashMap<>(); traverseNode(rootNode, "", result); return result; } catch (Exception e) { throw new IllegalArgumentException("JSON格式不合法,转换失败", e); } } /** * 递归遍历JsonNode树,拼接键名并收集叶子节点值 */ private static void traverseNode(JsonNode node, String currentPrefix, Map<String, String> result) { // 处理嵌套对象节点 if (node.isObject()) { Iterator<Map.Entry<String, JsonNode>> fieldIterator = node.fields(); while (fieldIterator.hasNext()) { Map.Entry<String, JsonNode> field = fieldIterator.next(); String fieldName = field.getKey(); JsonNode childNode = field.getValue(); // 拼接新的键前缀 String newPrefix = currentPrefix.isEmpty() ? fieldName : String.format("%s[%s]", currentPrefix, fieldName); traverseNode(childNode, newPrefix, result); } return; } // 叶子节点直接存入结果 result.put(currentPrefix, node.asText()); } }
使用示例
对应给出的Request和Person类,调用方式如下:
public class Test { public static void main(String[] args) throws Exception { // 构造测试对象 Person person = new Person(); person.setDob("1995-10-01"); person.setFirstName("San"); person.setLastName("Zhang"); Request request = new Request(); request.setTransactionId("TX20240001"); request.setPerson(person); // 直接从POJO转换 Map<String, String> formMap = FormFlatMapUtil.pojoToFormMap(request); /* 转换结果和手动put的内容完全一致: transaction_id = TX20240001 person[dob] = 1995-10-01 person[first_name] = San person[last_name] = Zhang */ // 从已序列化的JSON转换 String requestJson = OBJECT_MAPPER.writeValueAsString(request); Map<String, String> formMapFromJson = FormFlatMapUtil.jsonToFormMap(requestJson); } }
扩展说明
- 当前实现支持任意层级的对象嵌套,会自动生成
a[b][c]格式的合法表单键名 - 如果后续需要处理数组字段,只需在
traverseNode方法中增加数组节点的判断分支,按key[索引]的规则拼接键名即可 - 整个过程完全复用现有Jackson序列化配置,包括
@JsonProperty、命名策略等,不需要额外做适配
内容的提问来源于stack exchange,提问作者Alexander
相关产品推荐
相关产品推荐

