下面的库类允许数组和对象的深度合并。他们按照描述应用策略,但您可以通过更改方法中间的简单操作来采用自己的策略。
合并(覆盖或添加)的“覆盖”策略:
- 原始类型字段被覆盖。
- 具有相同声明键的对象被合并。
- 如果对象内容相等,则合并没有声明键的对象。
- 其他对象被覆盖或添加。
- 数组合并:在同一个数组中添加重复项,直到两个数组中此类项的数量相等。
用法(String或GsonJsonObject/JsonArray可以返回):
// Straightforward object merging:
Json.mergeObjects(
"{my_object_as_string}",
"{my_other_object_as_string}");
// Merge "my_objects" arrays and set object identity keys:
HashMap<String, String[]> keyCombinations = new HashMap<>();
keyCombinations.put(
"objects",
new String[] {"object_identity_key_one", "object_identity_key_two"});
Json.mergeArrays(
"my_objects",
keyCombinations,
"[my_array_as_string]",
"[my_other_array_as_string]"));
图书馆类:
package com.example.utils;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.HashMap;
import io.reactivex.annotations.NonNull;
@SuppressWarnings("unused")
public class Json {
/**
* Merge given JSON-objects. Same keys are merged for objects and
* overwritten by last object for primitive types.
*
* @param keyCombinations Key names for unique object identification.
* Or empty collection.
* @param objects Any amount of JSON-objects to merge.
*
* @return Merged JSON-object.
*/
public static JsonObject mergeObjects(
@NonNull
HashMap<String, String[]> keyCombinations,
Object... objects) {
JsonObject mergedObject = new JsonObject();
for (Object object : objects) {
JsonObject jsonObject = (JsonObject) object;
for (String key : jsonObject.keySet()) {
JsonElement parameter = jsonObject.get(key);
if (mergedObject.has(key)) {
// Key name matches:
if (jsonObject.get(key).isJsonObject()) {
// This is object - merge:
parameter =
mergeObjects(
keyCombinations,
mergedObject.get(key).getAsJsonObject(),
jsonObject.get(key).getAsJsonObject());
} else if (jsonObject.get(key).isJsonArray()) {
// This is array - merge:
parameter =
mergeArrays(
key,
keyCombinations,
mergedObject.get(key).getAsJsonArray(),
jsonObject.get(key).getAsJsonArray());
} else {
// This is neither object nor array - replace value:
mergedObject.add(key, parameter);
}
}
// No such field yet - add:
mergedObject.add(key, parameter);
}
}
return mergedObject;
}
/**
* Alternative - no object identity keys are set.
* See {@link Json#mergeObjects(HashMap, Object...)}
*/
public static JsonObject mergeObjects(
Object... objects) {
return (
mergeObjects(
new HashMap<>(),
objects));
}
/**
* Get GSON-object from string.
*
* @param jsonString JSON-object as string.
*
* @return JsonObject (GSON).
*/
public static JsonObject getJsonObject(String jsonString) {
JsonObject jsonObject = new JsonObject();
JsonParser parser;
parser = new JsonParser();
if (jsonString != null) {
jsonObject =
parser
.parse(
jsonString)
.getAsJsonObject();
}
return jsonObject;
}
/**
* See {@link Json#mergeObjects(HashMap, Object...)}
*/
public static String mergeObjects(
HashMap<String, String[]> keyCombinations,
String... jsonObjects) {
ArrayList<JsonObject> objects = new ArrayList<>();
for (String jsonObject : jsonObjects) {
objects.add(
Json2.getJsonObject(jsonObject));
}
return (
mergeObjects(
keyCombinations,
objects.toArray())
.toString());
}
/**
* Alternative - no object identity keys are set.
* See {@link Json#mergeObjects(HashMap, Object...)}
*/
public static String mergeObjects(
String... jsonObjects) {
ArrayList<JsonObject> objects = new ArrayList<>();
for (String jsonObject : jsonObjects) {
objects.add(
getJsonObject(jsonObject));
}
return (
mergeObjects(
new HashMap<>(),
objects.toArray())
.toString());
}
/**
* See {@link Json#mergeArrays(String, HashMap, Object...)}
*/
public static String mergeArrays(
String arrayName,
HashMap<String, String[]> keyCombinations,
String... jsonArrays) {
ArrayList<JsonArray> arrays = new ArrayList<>();
for (String jsonArray : jsonArrays) {
arrays.add(
getJsonArray(jsonArray));
}
return (
mergeArrays(
arrayName,
keyCombinations,
arrays.toArray())
.toString());
}
/**
* Alternative - no object identity keys are set.
* See {@link Json#mergeArrays(String, HashMap, Object...)}
*/
public static String mergeArrays(
String... jsonArrays) {
ArrayList<JsonArray> arrays = new ArrayList<>();
for (String jsonArray : jsonArrays) {
arrays.add(
getJsonArray(jsonArray));
}
return (
mergeArrays(
"",
new HashMap<>(),
arrays.toArray())
.toString());
}
/**
* Alternative - no object identity keys are set.
* Seee {@link Json#mergeArrays(String, HashMap, Object...)}
*/
public static JsonArray mergeArrays(
Object... jsonArrays) {
return (
mergeArrays(
"",
new HashMap<>(),
jsonArrays));
}
/**
* Merge arrays following "Overlay" strategy (overwrite or add).
* Duplicate elements are added to array until their amount is equal
* in both arrays. Objects are considered identical if their
* identifier-keys are present and their values are equal. If no such
* keys, then objects are considered identical on equal content.
*
* @param arrayName Merged arrays name or empty string.
* Used to choose from key combinations.
* @param keyCombinations Array objects identifier-key names.
* @param jsonArrays Any amount of JSON-arrays to merge.
*
* @return Merged array.
*/
public static JsonArray mergeArrays(
@NonNull
String arrayName,
@NonNull
HashMap<String, String[]> keyCombinations,
Object... jsonArrays) {
JsonArray resultArray = new JsonArray();
for (Object jsonArray : jsonArrays) {
JsonArray array = (JsonArray) jsonArray;
for (JsonElement item : array) {
if (
item.isJsonObject() &&
keyCombinations.get(arrayName) != null &&
keyCombinations.get(arrayName).length > 0) {
// Array element is an object with identifier-keys:
ArrayList<JsonElement> resultArrayObjectsFound =
getArrayObjectsByKeyValues(
resultArray,
item.getAsJsonObject(),
keyCombinations.get(arrayName));
if (resultArrayObjectsFound.size() > 0) {
// Such field is already present, merge is required:
JsonObject resultArrayObjectFound =
resultArrayObjectsFound.get(0).getAsJsonObject();
JsonObject mergedObject =
mergeObjects(
keyCombinations,
resultArrayObjectFound,
item.getAsJsonObject());
resultArray.remove(resultArrayObjectFound);
resultArray.add(mergedObject);
continue;
}
}
if (!resultArray.contains(item)) {
// No such element - add:
resultArray.add(item);
} else if (
count(resultArray, item) < count(array, item)) {
// There are more duplicates of the element - add:
resultArray.add(item);
}
}
}
return resultArray;
}
/**
* Convert String to JSON-Array (GSON).
*
* @param jsonString JSON-array as string.
*
* @return JSON-array as GSON-array.
*/
public static JsonArray getJsonArray(String jsonString) {
JsonArray jsonArray = new JsonArray();
JsonParser parser;
parser = new JsonParser();
try {
jsonArray =
parser
.parse(
jsonString)
.getAsJsonArray();
} catch (Exception ignore) {
}
return jsonArray;
}
/**
* Find array objects that have required identity keys and match the values.
*
* @param array Array to search in.
* @param object Example object for search.
* Contains required keys and values.
* @param keys Object identity keys.
*
* @return Matching JSON-elements.
*/
public static ArrayList<JsonElement> getArrayObjectsByKeyValues(
JsonArray array,
JsonObject object,
String[] keys) {
ArrayList<JsonElement> elements = new ArrayList<>();
for (JsonElement arrayElement : array) {
if (arrayElement.isJsonObject()) {
JsonObject jsonObject = arrayElement.getAsJsonObject();
boolean hasAllKeysThatMatch = true;
for (String key : keys) {
if (!jsonObject.has(key)) {
// One of the keys is not found:
hasAllKeysThatMatch = false;
break;
} else {
if (
jsonObject.get(key).isJsonPrimitive() &&
!jsonObject.get(key).equals(object.get(key))) {
// Primitive type key values don't match:
hasAllKeysThatMatch = false;
break;
}
if ((
jsonObject.get(key).isJsonObject() ||
jsonObject.get(key).isJsonArray()) &&
!jsonObject.get(key).toString().equals(
object.get(key).toString())) {
// Complex type key values don't match:
hasAllKeysThatMatch = false;
break;
}
}
}
if (hasAllKeysThatMatch) {
// Key values match:
elements.add(jsonObject);
}
}
}
return elements;
}
/**
* Count given elements in array.
*
* @param element Element to find.
*
* @return Amount of given elements in array.
*/
public static int count(
JsonArray array,
JsonElement element) {
int count = 0;
for (JsonElement currentElement : array) {
if (currentElement.isJsonPrimitive()) {
// Primitive type:
if (currentElement.equals(element)) {
count++;
}
}
if (
currentElement.isJsonObject() ||
currentElement.isJsonArray()) {
// Complex type:
if (currentElement.toString().equals(element.toString())) {
count++;
}
}
}
return count;
}
}