我在使用芭乐的Maps.difference时遇到了一些问题
现在,使用下面的代码比较来自两个不同jsons的两个HashMaps:
//Create maps from the given jsons
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> map1 = gson.fromJson(jsonObject1, type);
Map<String, Object> map2 = gson.fromJson(jsonObject2, type);
//Flatten the maps
Map<String, Object> leftFlatMap = FlatMap.flatten(map1);
Map<String, Object> rightFlatMap = FlatMap.flatten(map2);
//Check differences between both maps
MapDifference<String, Object> difference = Maps.difference(leftFlatMap, rightFlatMap);一切运行正常,并且(几乎)正确地比较了所有元素。问题是当HashMap中的一个元素是一个映射数组时,这些元素是相同的,但顺序不同。如下所示:
第一个JSON:
{ "body":[
{
"primitive":"VALUE",
"jsonArray":[
{
"element":83284180
},
{
"anotherElement":20832841804
}
]
}
]
}第二个JSON:
{
"body":[
{
"primitive":"VALUE",
"jsonArray":[
{
"anotherElement":20832841804
},
{
"element":83284180
}
]
}
]
}正如您所看到的,element和anotherElement的值是相同的,但是由于它们在数组中的出现顺序不同,所以difference会显示一个错误。

之前有没有可能对数组进行排序?或任何其他解决方案?
提前感谢!!
发布于 2021-05-27 04:45:43
一种可能的解决方案可能是对内部子数组进行排序,以便影响反序列化映射(然而,我认为在这种情况下从JSON对象生成映射可能不是一个很好的主意,因为反序列化成本和策略不一定代表原始JSON对象)。
假设jsonObject1和jsonObject2是JsonElement实现,您可以对其后代进行排序。
@UtilityClass
public final class JsonElements {
public static List<JsonElement> asListView(final JsonArray jsonArray) {
return new JsonArrayListView(jsonArray);
}
public static void sort(final JsonArray jsonArray, final Comparator<? super JsonElement> comparator) {
Collections.sort(asListView(jsonArray), comparator);
}
@AllArgsConstructor(access = AccessLevel.PRIVATE)
private static final class JsonArrayListView
extends AbstractList<JsonElement> {
private final JsonArray jsonArray;
@Override
public JsonElement get(final int index) {
return jsonArray.get(index);
}
@Override
public int size() {
return jsonArray.size();
}
@Override
@SuppressWarnings("MethodDoesntCallSuperMethod")
public JsonElement set(final int index, final JsonElement element) {
return jsonArray.set(index, element);
}
}
}public final class JsonElementsTest {
private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.disableInnerClassSerialization()
.create();
private static final Type stringToObjectMapType = new TypeToken<Map<String, Object>>() {}.getType();
@Test
public void testSort()
throws IOException {
final JsonElement jsonElement1 = ... read the 1st JSON document ...;
final JsonElement jsonElement2 = ... read the 2nd JSON document ...;
final JsonArray jsonSubArray1 = getSubArray(jsonElement1);
final JsonArray jsonSubArray2 = getSubArray(jsonElement2);
Assertions.assertNotEquals(jsonSubArray1, jsonSubArray2);
JsonElements.sort(jsonSubArray1, JsonElementsTest::compare);
JsonElements.sort(jsonSubArray2, JsonElementsTest::compare);
final Map<String, Object> map1 = gson.fromJson(jsonElement1, stringToObjectMapType);
final Map<String, Object> map2 = gson.fromJson(jsonElement2, stringToObjectMapType);
Assertions.assertEquals(map1, map2);
}
private static JsonArray getSubArray(final JsonElement jsonElement) {
return jsonElement.getAsJsonObject()
.get("body")
.getAsJsonArray()
.get(0)
.getAsJsonObject()
.get("jsonArray")
.getAsJsonArray();
}
private static int compare(final JsonElement jsonElement1, final JsonElement jsonElement2)
throws IllegalArgumentException {
final JsonObject jsonObject1 = jsonElement1.getAsJsonObject();
final int size1 = jsonObject1.size();
if ( size1 != 1 ) {
throw new IllegalArgumentException("Size-1 must equal 1, but was " + size1);
}
final JsonObject jsonObject2 = jsonElement2.getAsJsonObject();
final int size2 = jsonObject2.size();
if ( size2 != 1 ) {
throw new IllegalArgumentException("Size-2 must equal 2, but was " + size2);
}
// TODO optimize somehow
final String key1 = jsonObject1.keySet().iterator().next();
final String key2 = jsonObject2.keySet().iterator().next();
return key1.compareTo(key2);
}
}如果有必要,还可以考虑递归地对子代进行排序。
注意,对于给定的JSON文档,您可能也有一个映射,但我不认为这是您的情况,但如果是这样,那么您可能希望应用@JsonAdapter来应用一个特殊的排序反序列化程序(但是我仍然不认为这也是一个好主意)。或者,也可以为给定的JsonObject创建映射视图,以便它可以生成递归重新排序视图。
https://stackoverflow.com/questions/67707652
复制相似问题