当前位置: 首页 > 工具软件 > JSON Patch > 使用案例 >

通过JSONDiff获取JSONPatch

江阳羽
2023-12-01

前言

最近看了一下fabric8的源码,发现对于k8s资源的更新都是采用了JSONPatch的方式,看是市面上却没有关于JSONPatch一键使用的工具类,所以自己搜了一下GitHub上开源的项目和自己的研究,写了一个方便易用的工具类,以方便大家的ctrl+C, ctrl+V。

依赖

用的依赖为zjsonpath,其中封装了有关JSONDiff的方法;

<!-- json Patch -->
        <dependency>
            <groupId>com.flipkart.zjsonpatch</groupId>
            <artifactId>zjsonpatch</artifactId>
            <version>0.4.12</version>
        </dependency>

代码

JSONPatch Model类

@Data
public class JSONPatch {
    /*
     * RFC6902 - 4.
     */
    private String op;
    private String path;
    private Object value;
}

JSONPatch工具类

package com.victor.util;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flipkart.zjsonpatch.JsonDiff;
import com.flipkart.zjsonpatch.JsonPatch;
import com.victor.model.JSONPatch;

import java.util.List;

/**
 * JSONPatch工具类,主要为两个功能:
 * 1.通过源对象和目标对象获得JSONPatch, JSONPath可以是数组或字符串;
 * 2.根据源对象, 通过JSONPatch字符串或数组获得目标对象;
 *
 */
public class JSONPatchUtil {

    private static final ObjectMapper MAPPER = new ObjectMapper();

    /**
     * 将两个对象之间的差别以JSONPatch的形式呈现
     *
     * @param source 老对象
     * @param target 新对象
     * @return List<JSONPatch>
     */
    public static List<JSONPatch> getJSONPatch(Object source, Object target) {
        try {
            JsonNode oldJson = MAPPER.valueToTree(source);
            JsonNode newJson = MAPPER.valueToTree(target);
            JsonNode jsonNode = JsonDiff.asJson(oldJson, newJson);
            String jsonPatchStr = MAPPER.writeValueAsString(jsonNode);

            return MAPPER.readValue(jsonPatchStr, new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将两个对象之间的差别以JSONPatch字符串的形式呈现
     *
     * @param source 老对象
     * @param target 新对象
     * @return List<JSONPatch>的json形式
     */
    public static String getJSONPatchStr(Object source, Object target) {
        try {
            JsonNode oldJson = MAPPER.valueToTree(source);
            JsonNode newJson = MAPPER.valueToTree(target);
            JsonNode jsonNode = JsonDiff.asJson(oldJson, newJson);
            return MAPPER.writeValueAsString(jsonNode);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 应用JSONPatch生成目标对象
     *
     * @param patch  JSONPatch字符串表达形式
     * @param source 原对象
     * @param <T>    源对象和目标对象的类型
     * @return 目标对象
     */
    public static <T> T applyJSONPatch(String patch, T source) {
        try {
            JsonNode oldJson = MAPPER.valueToTree(source);
            JsonNode patchJson = MAPPER.readTree(patch);
            JsonNode newJson = JsonPatch.apply(patchJson, oldJson);
            String targetStr = MAPPER.writeValueAsString(newJson);
            return MAPPER.readValue(targetStr, new TypeReference<>() {
            });
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 应用JSONPatch生成目标对象
     *
     * @param patch  JSONPatch数组表达形式
     * @param source 原对象
     * @param <T>    源对象和目标对象的类型
     * @return 目标对象
     */
    public static <T> T applyJSONPatch(List<JSONPatch> patch, T source) {
        try {
            return applyJSONPatch(MAPPER.writeValueAsString(patch), source);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }
}

测试用例

package com.victor.json;

import cn.hutool.setting.yaml.YamlUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.flipkart.zjsonpatch.JsonDiff;
import com.victor.model.JSONPatch;
import com.victor.util.JSONPatchUtil;
import org.testng.annotations.Test;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @description:
 */
@SuppressWarnings("rawtypes")
public class JSONPatchTest {

    private final ObjectMapper objectMapper = SingletonHolder.patchMapper;
    private final Map oldObj = YamlUtil.loadByPath("test1.yaml", Map.class);
    private final Map newObj = YamlUtil.loadByPath("test2.yaml", Map.class);
    
    @Test
    public void testJSONPatchStr() {
        String s = JSONPatchUtil.getJSONPatchStr(oldObj, newObj);
        System.out.println(s);
    }

    @Test
    public void testJSONPatch() {
        List<JSONPatch> jsonPatch = JSONPatchUtil.getJSONPatch(oldObj, newObj);
        System.out.println(jsonPatch);
    }

    @Test
    public void applyJSONPatchStr() {
        String patch = JSONPatchUtil.getJSONPatchStr(oldObj, newObj);
        Map map = JSONPatchUtil.applyJSONPatch(patch, oldObj);
        System.out.println(newObj.equals(map));
    }

    @Test
    public void applyJSONPatch() {
        List<JSONPatch> patch = JSONPatchUtil.getJSONPatch(oldObj, newObj);
        Map map = JSONPatchUtil.applyJSONPatch(patch, oldObj);
        System.out.println(newObj.equals(map));
    }
}

 类似资料: