在Java中使用Gson合并/扩展JSON对象

bra*_*ido 6 java merge json gson

通常,我需要合并两个JSON对象(类似于jQuery的$.extend()工作方式).但是,Gson库没有内置功能,他们说他们不会实现它.

做类似的事情:

private void merge(JsonObject firstObj, JsonObject secondObj){
    for(String keyInSecondObj : secondObj.entrySet().keySet()) {
      if(!firstObj.has(keyInSecondObj )){
        firstObj.add(secondMap.get(keyInSecondObj));
    }
}
Run Code Online (Sandbox Code Playgroud)

太简单了,因为它不处理递归合并JsonObjects,当两个映射中都存在键时不处理冲突,并且没有对非原始值(如Arrays)进行特殊处理.

我没有找到任何预先构建的解决方案来做到这一点.我更喜欢使用已经过彻底测试的东西,而不是编写我自己的方法,但它必须是Gson(不是Jackson或其他).

编辑:我最后编写了自己的实现,因为已经添加了作为这个问题答案

这个问题不是因为它不使用GSON(或Java为此事)中的重复.

bra*_*ido 12

这是我第一次尝试编写自己的静态合并方法.随意戳它的洞.

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.Map;

public class GsonTools {

    public static enum ConflictStrategy {

        THROW_EXCEPTION, PREFER_FIRST_OBJ, PREFER_SECOND_OBJ, PREFER_NON_NULL;
    }

    public static class JsonObjectExtensionConflictException extends Exception {

        public JsonObjectExtensionConflictException(String message) {
            super(message);
        }

    }

    public static void extendJsonObject(JsonObject destinationObject, ConflictStrategy conflictResolutionStrategy, JsonObject ... objs) 
            throws JsonObjectExtensionConflictException {
        for (JsonObject obj : objs) {
            extendJsonObject(destinationObject, obj, conflictResolutionStrategy);
        }
    }

    private static void extendJsonObject(JsonObject leftObj, JsonObject rightObj, ConflictStrategy conflictStrategy) 
            throws JsonObjectExtensionConflictException {
        for (Map.Entry<String, JsonElement> rightEntry : rightObj.entrySet()) {
            String rightKey = rightEntry.getKey();
            JsonElement rightVal = rightEntry.getValue();
            if (leftObj.has(rightKey)) {
                //conflict                
                JsonElement leftVal = leftObj.get(rightKey);
                if (leftVal.isJsonArray() && rightVal.isJsonArray()) {
                    JsonArray leftArr = leftVal.getAsJsonArray();
                    JsonArray rightArr = rightVal.getAsJsonArray();
                    //concat the arrays -- there cannot be a conflict in an array, it's just a collection of stuff
                    for (int i = 0; i < rightArr.size(); i++) {
                        leftArr.add(rightArr.get(i));
                    }
                } else if (leftVal.isJsonObject() && rightVal.isJsonObject()) {
                    //recursive merging
                    extendJsonObject(leftVal.getAsJsonObject(), rightVal.getAsJsonObject(), conflictStrategy);
                } else {//not both arrays or objects, normal merge with conflict resolution
                    handleMergeConflict(rightKey, leftObj, leftVal, rightVal, conflictStrategy);
                }
            } else {//no conflict, add to the object
                leftObj.add(rightKey, rightVal);
            }
        }
    }

    private static void handleMergeConflict(String key, JsonObject leftObj, JsonElement leftVal, JsonElement rightVal, ConflictStrategy conflictStrategy) 
            throws JsonObjectExtensionConflictException {
        {
            switch (conflictStrategy) {
                case PREFER_FIRST_OBJ:
                    break;//do nothing, the right val gets thrown out
                case PREFER_SECOND_OBJ:
                    leftObj.add(key, rightVal);//right side auto-wins, replace left val with its val
                    break;
                case PREFER_NON_NULL:
                    //check if right side is not null, and left side is null, in which case we use the right val
                    if (leftVal.isJsonNull() && !rightVal.isJsonNull()) {
                        leftObj.add(key, rightVal);
                    }//else do nothing since either the left value is non-null or the right value is null
                    break;
                case THROW_EXCEPTION:
                    throw new JsonObjectExtensionConflictException("Key " + key + " exists in both objects and the conflict resolution strategy is " + conflictStrategy);
                default:
                    throw new UnsupportedOperationException("The conflict strategy " + conflictStrategy + " is unknown and cannot be processed");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Via*_*nin 5

您可以使用

  Map firstObject = new GSON().fromJson(json1, HashMap.class);
  Map secondObject = new GSON().fromJson(json2, HashMap.class);
Run Code Online (Sandbox Code Playgroud)

// 根据需要合并 Map firstObject 和 secondObject,请参阅此帖子

  String resultJson = new GSON().toJson(resultMap); 
Run Code Online (Sandbox Code Playgroud)

  • 这种策略很幼稚,因为它只是将第二张地图中存在的任何值添加到第一张地图。如果存在冲突(两个对象中都存在),或者值是非原始值(递归对象合并和数组连接),它不会处理该怎么做 (2认同)
  • 是的,但是您可以手动合并 conflit,只需使用合并两个 HashMap (2认同)
  • 用手!?真的吗? (2认同)