ObjectMapper的objectNode、ArrayNode各种转换使用

在这里插入图片描述

说明

本文章代码出自摸石头过河写出来的,隔天再写不一定写得出来,所以发个文章记录下。

为什么写这个代码
需求要求,有一段json字符串,数据结构是图下这样:

{
	"id": "1",
	"string": "sb",
	"double": "33",
	"long": "2",
	"boolean": "true",
	"domain": {
		"id": "1",
		"name": "大白",
		"org": {
			"code": "1"
		},
		"jd": [{
			"j": "false",
			"d": "4"
		}, {
			"j": "true",
			"d": "6"
		}]
	},
	"orgs": [{
		"code": "bb",
		"id": "true",
		"org": {
			"code": "1"
		},
		"sb": [{
			"s": "1"
		}, {
			"b": "true"
		}]
	}, {
		"code": "cc",
		"id": "false",
		"org": {
			"code": "1"
		},
		"sb": [{
			"s": "2"
		}, {
			"b": "false"
		}]
	}]
}

可以得知,所有属性都是string类型,又得知有个Attr类,里面放着json属性对应的类型,要求我们如果json里面有属性和Attr类里面名称对应的上,就要把string转换相对应的类型。

以上可能有点绕,举个栗子:图上有个id的属性,它的值是字符串的1,Attr类里面id对应的值是integer,所以最后的结果要是integer类型。

由于json数据结构不可知,只能穷举+递归针对处理:
1、基本数据类型
2、object类型
3、array类型
4、object类型中有array类型
5、array类型中有object类型

实例代码

package com.lq.demo1.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lq.demo1.entity.Attr;
import com.lq.demo1.entity.Constants;
import lombok.extern.slf4j.Slf4j;

import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class TestService {


    public static void main(String[] args) throws JsonProcessingException {

        String json = "{\n" +
                "\t\"id\": \"1\",\n" +
                "\t\"string\": \"sb\",\n" +
                "\t\"double\": \"33\",\n" +
                "\t\"long\": \"2\",\n" +
                "\t\"boolean\": \"true\",\n" +
                "\t\"domain\": {\n" +
                "\t\t\"id\": \"1\",\n" +
                "\t\t\"name\": \"大白\",\n" +
                "\t\t\"org\": {\n" +
                "\t\t\t\"code\": \"1\"\n" +
                "\t\t},\n" +
                "\t\t\"jd\": [{\n" +
                "\t\t\t\"j\": \"false\",\n" +
                "\t\t\t\"d\": \"4\"\n" +
                "\t\t}, {\n" +
                "\t\t\t\"j\": \"true\",\n" +
                "\t\t\t\"d\": \"6\"\n" +
                "\t\t}]\n" +
                "\t},\n" +
                "\t\"orgs\": [{\n" +
                "\t\t\"code\": \"bb\",\n" +
                "\t\t\"id\": \"true\",\n" +
                "\t\t\"org\": {\n" +
                "\t\t\t\"code\": \"1\"\n" +
                "\t\t},\n" +
                "\t\t\"sb\": [{\n" +
                "\t\t\t\"s\": \"1\"\n" +
                "\t\t}, {\n" +
                "\t\t\t\"b\": \"true\"\n" +
                "\t\t}]\n" +
                "\t}, {\n" +
                "\t\t\"code\": \"cc\",\n" +
                "\t\t\"id\": \"false\",\n" +
                "\t\t\"org\": {\n" +
                "\t\t\t\"code\": \"1\"\n" +
                "\t\t},\n" +
                "\t\t\"sb\": [{\n" +
                "\t\t\t\"s\": \"2\"\n" +
                "\t\t}, {\n" +
                "\t\t\t\"b\": \"false\"\n" +
                "\t\t}]\n" +
                "\t}]\n" +
                "}";

        log.info("老:{}", json);
        ObjectMapper objectMapper = new ObjectMapper();
        ObjectNode objectNode = (ObjectNode) objectMapper.readTree(json);

        Attr a = Attr.builder().id(1).attributeName("id").attributeType("INTEGER").parentId(-1).build();
        Attr b = Attr.builder().id(2).attributeName("string").attributeType("STRING").parentId(-1).build();
        Attr c = Attr.builder().id(3).attributeName("double").attributeType("INTEGER").parentId(-1).build();
        Attr d = Attr.builder().id(4).attributeName("long").attributeType("LONG").parentId(-1).build();
        Attr e = Attr.builder().id(5).attributeName("boolean").attributeType("BOOLEAN").parentId(-1).build();

        Attr f = Attr.builder().id(6).attributeName("orgs").attributeType("JSONARRAY").parentId(-1).build();
        Attr g = Attr.builder().id(7).attributeName("code").attributeType("STRING").parentId(6).build();
        Attr h = Attr.builder().id(7).attributeName("id").attributeType("BOOLEAN").parentId(6).build();
        Attr l1 = Attr.builder().id(13).attributeName("org").attributeType("JSONOBJECT").parentId(6).build();
        Attr m1 = Attr.builder().id(14).attributeName("code").attributeType("INTEGER").parentId(13).build();
        Attr m11 = Attr.builder().id(15).attributeName("sb").attributeType("JSONARRAY").parentId(6).build();
        Attr m12 = Attr.builder().id(16).attributeName("s").attributeType("INTEGER").parentId(15).build();
        Attr m13 = Attr.builder().id(17).attributeName("b").attributeType("BOOLEAN").parentId(15).build();


        Attr i = Attr.builder().id(8).attributeName("domain").attributeType("JSONOBJECT").parentId(-1).build();
        Attr j = Attr.builder().id(9).attributeName("id").attributeType("INTEGER").parentId(8).build();
        Attr k = Attr.builder().id(10).attributeName("name").attributeType("STRING").parentId(8).build();
        Attr l = Attr.builder().id(11).attributeName("org").attributeType("JSONOBJECT").parentId(8).build();
        Attr m = Attr.builder().id(12).attributeName("code").attributeType("INTEGER").parentId(11).build();
        Attr m8 = Attr.builder().id(18).attributeName("jd").attributeType("JSONARRAY").parentId(8).build();
        Attr m9 = Attr.builder().id(19).attributeName("j").attributeType("BOOLEAN").parentId(18).build();
        Attr m20 = Attr.builder().id(20).attributeName("d").attributeType("INTEGER").parentId(18).build();


        List<Attr> attrs = new LinkedList<>();
        attrs.add(m8);
        attrs.add(m9);
        attrs.add(m20);

        attrs.add(a);
        attrs.add(b);
        attrs.add(c);
        attrs.add(d);
        attrs.add(e);
        attrs.add(f);
        attrs.add(g);
        attrs.add(h);
        attrs.add(i);
        attrs.add(j);
        attrs.add(k);
        attrs.add(l);
        attrs.add(m);
        attrs.add(l1);
        attrs.add(m1);
        attrs.add(m11);
        attrs.add(m12);
        attrs.add(m13);
        tree(attrs);
        log.info("树结构:{}", attrs.toString());

        Iterator<Map.Entry<String, JsonNode>> fields = objectNode.fields();
        while (fields.hasNext()) {
            Map.Entry<String, JsonNode> next = fields.next();
            String key = next.getKey();
            JsonNode value = next.getValue();
            for (Attr dto : attrs) {
                String attributeType = dto.getAttributeType();
                if (dto.getAttributeName().equals(key)) {
                    if (!attributeType.equals(Constants.JSONARRAY) && !attributeType.equals(Constants.JSONOBJECT)) {
                        //先把最外层的基本类型给解决掉
                        baseNode(objectNode, key, value, attributeType);
                    } else if (attributeType.equals(Constants.JSONOBJECT)) {
                        //第一层的key
                        objectNode(objectNode, key, key, value, attributeType, attrs);
                    } else if (attributeType.equals(Constants.JSONARRAY)) {
                        arraryNode(objectNode, key, key, attributeType, attrs);
                    }
                }
            }
        }

        log.info("新:{}", objectNode.toString());
    }

    /**
     * @param objectNode      原始数据
     * @param key           原始数据中的key
     * @param value         key的value 需要转换类型
     * @param attributeType 转换的类型
     */
    public static void baseNode(ObjectNode objectNode, String key, JsonNode value, String attributeType) {
        //基础类型设置值
        if (attributeType.equals(Constants.DOUBLE)) {
            objectNode.put(key, value.asDouble());
        } else if (attributeType.equals(Constants.INTEGER)) {
            objectNode.put(key, value.asInt());
        } else if (attributeType.equals(Constants.LONG)) {
            objectNode.put(key, value.asLong());
        } else if (attributeType.equals(Constants.BOOLEAN)) {
            objectNode.put(key, value.asBoolean());
        }
    }

    /**
     * @param rootObjectNode      原始数据
     * @param rootKey       原始数据中key
     * @param attrKey       追加要和attr name 拼接使用的key
     * @param attributeType
     * @param attrs
     */
    public static void arraryNode(ObjectNode rootObjectNode, String rootKey, String attrKey, String attributeType, List<Attr> attrs) {
        if (attributeType.equals(Constants.JSONARRAY)) {
            ArrayNode jsonNodes = rootObjectNode.withArray(rootKey);
            for (int i = 0; i < jsonNodes.size(); i++) {
                JsonNode node = jsonNodes.get(i);
                Iterator<Map.Entry<String, JsonNode>> fields = node.fields();
                while (fields.hasNext()) {
                    Map.Entry<String, JsonNode> next = fields.next();
                    String key = next.getKey();
                    String dkey = attrKey + "." + key;
                    //子属性node
                    JsonNode nextValue = next.getValue();
                    for (Attr attr : attrs) {
                        if (dkey.equals(attr.getAttributeName())) {
                            String attributeType1 = attr.getAttributeType();
                            if (!attributeType1.equals(Constants.JSONOBJECT) && !attributeType1.equals(Constants.JSONARRAY)) {
                                //怎么修改值类型?
                                ObjectNode objectNode = (ObjectNode) node;
                                if (attributeType1.equals(Constants.DOUBLE)) {
                                    objectNode.put(key, nextValue.asInt());
                                } else if (attributeType1.equals(Constants.INTEGER)) {
                                    objectNode.put(key, nextValue.asInt());
                                } else if (attributeType1.equals(Constants.LONG)) {
                                    objectNode.put(key, nextValue.asLong());
                                } else if (attributeType1.equals(Constants.BOOLEAN)) {
                                    objectNode.put(key, nextValue.asBoolean());
                                } else if (attributeType1.equals(Constants.STRING)) {
                                    objectNode.put(key, nextValue.asText());
                                }
                            } else if (attributeType1.equals(Constants.JSONOBJECT)) {
                                ObjectNode objectNode = (ObjectNode) node;
                                objectNode(objectNode, key, dkey, nextValue, attributeType1, attrs);
                            } else if (attributeType1.equals(Constants.JSONARRAY)) {
                                ObjectNode objectNode = (ObjectNode) node;
                                arraryNode(objectNode, key, dkey, attributeType1, attrs);
                            }
                        }
                    }
                }
            }
        }

    }


    /**
     * @param rootObjectNode      原始数据
     * @param rootKey       对象名称
     * @param attrKey
     * @param childJsonNode 对象里面的所有属性
     * @param attributeType
     * @param attrs
     */
    public static void objectNode(ObjectNode rootObjectNode, String rootKey, String attrKey, JsonNode childJsonNode,
                              String attributeType, List<Attr> attrs) {
        if (attributeType.equals(Constants.JSONOBJECT)) {
            Iterator<Map.Entry<String, JsonNode>> fields = childJsonNode.fields();
            while (fields.hasNext()) {
                Map.Entry<String, JsonNode> next = fields.next();
                String key = next.getKey();
                String dkey = attrKey + "." + key;
                //子属性node
                JsonNode nextValue = next.getValue();
                for (Attr attr : attrs) {
                    if (dkey.equals(attr.getAttributeName())) {
                        String attributeType1 = attr.getAttributeType();
                        if (!attributeType1.equals(Constants.JSONOBJECT) && !attributeType1.equals(Constants.JSONARRAY)) {
                            ObjectNode objectNode = rootObjectNode.with(rootKey);
                            if (attributeType1.equals(Constants.DOUBLE)) {
                                objectNode.put(key, nextValue.asDouble());
                            } else if (attributeType1.equals(Constants.INTEGER)) {
                                objectNode.put(key, nextValue.asInt());
                            } else if (attributeType1.equals(Constants.LONG)) {
                                objectNode.put(key, nextValue.asLong());
                            } else if (attributeType1.equals(Constants.BOOLEAN)) {
                                objectNode.put(key, nextValue.asBoolean());
                            }
                        } else if (attributeType1.equals(Constants.JSONOBJECT)) {
                            ObjectNode objectNode = rootObjectNode.with(rootKey);
                            objectNode(objectNode, key, dkey, nextValue, attributeType1, attrs);
                        } else if (attributeType1.equals(Constants.JSONARRAY)) {
                            ObjectNode objectNode = rootObjectNode.with(rootKey);
                            arraryNode(objectNode, key, dkey, attributeType1, attrs);
                        }
                    }
                }
            }
        }
    }

    /**
     * 树节点处理名称拼接  查询sql的id必须按照升序排序 不然方法无效
     *
     * @param all
     */
    public static void tree(List<Attr> all) {
        //按照id升序 因为Attr是类似tree结构的数据,如果是object类型,一个属性的名称例如就是domain.id  为什么不直接拿id,因为不同节点id可能是string可能是integer,所以要通过对象.属性去重命名  外面匹配也是一样,如果有嵌套的数据,要自行处理名称和Attr重置后的名称匹配,才能得知真正类型是什么
        all.stream().sorted(Comparator.comparing(Attr::getId)).collect(Collectors.toList());
        for (Attr a : all) {
            if (a.getParentId().intValue() != -1) {
                setName(a, all);
            }
        }
    }

    public static void setName(Attr b, List<Attr> all) {
        for (Attr attribute : all) {
            if (b.getParentId().equals(attribute.getId())) {
                b.setAttributeName(attribute.getAttributeName() + "." + b.getAttributeName());
            }
        }
    }
}

主要难点,就是objectNode和arrayNode怎么去设置值,当时困扰了我很久,因为对ObjectMapper不熟悉,里面很多方法不知道,后面看了下源码才知道,主要的坑有以下几点:

  1. 所有的数据修改,都可以用ObjectNode.put方法去改,即使是arrayNode类型,之前不知道怎么去修改,妄想自己组装map去覆盖,结果失败。。
  2. 递归传递的值一定要捋清楚,很容易穿错原数据结构,比如对象套对象、对象套集合、集合套对象套集合等等这种很扭曲很恶心的结构,在针对对象和集合这两个类型卡我很久!!!
  3. JsonNode可以强转换为ObjectNode类型,之后就可以针对这个节点的值去修改,例如arrayNode我一直在查怎么修改,很多人都说删除原节点,自己写个新的节点加进去,这种很麻烦很麻烦很麻烦,尤其各种变态结构,极其容易出错(我没写成功过)
  4. ObjectNode.with、ObjectNode.withArray是object、array类型获取节点不同方式,里面填的是key名称,会去同一层找到这个key的所有属性返回,这个就是从源码看到的,百度我没找到,各个类去翻才找到。。。
  5. 如何去循环一个node,方法是JsonNode.fields();,JsonNode里面有很多方法,可以去源码看看,也有拿所有key的,但是 JsonNode.fields(); 能拿到所有的key-value键值对,其他的要么只能拿key,要么只能拿value,而且value还不是jsonNode类型,后面极其不好处理

就先说到这 \color{#008B8B}{ 就先说到这} 就先说到这
在下 A p o l l o \color{#008B8B}{在下Apollo} 在下Apollo
一个爱分享 J a v a 、生活的小人物, \color{#008B8B}{一个爱分享Java、生活的小人物,} 一个爱分享Java、生活的小人物,
咱们来日方长,有缘江湖再见,告辞! \color{#008B8B}{咱们来日方长,有缘江湖再见,告辞!} 咱们来日方长,有缘江湖再见,告辞!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值