【问题标题】:How to compare Json Arrays having elements not in same order如何比较具有不同顺序元素的Json数组
【发布时间】:2020-03-23 20:04:44
【问题描述】:

我有 2 个 API 响应并将它们转换为 Json 数组。当我将 2 个 json 转换为键值对映射时,值的顺序不同,无法在 2 个 API 响应之间进行比较。

来自 API 1 的 JsonArray:

[
 {
  "employeeSalutation": null,
  "EmployeeName": "Example",
  "EmployeeCode": "SAA",
  "Zip": 12345,
  "DepartmentName": "Social science",
  "EmployeeAddress": "123 st",
  "StateCode": 9,
  "updatedDate": "2018-01-22T03:48:43.59",
  "EmployeeId": 1257
 }
]

来自 API 2 的 JSON 数组:

[
 {
  "Emp_Name": "Example",
  "emp_Sal": null,
  "Dept_Name": "Social science",
  "Emp_addr": "123 st",
  "Zip": "12345",
  "Stat_cd": 9,
  "Emp_id": 1257,
  "upd_d": "2018-01-22 03:48:43.59",
  "Emp_Code": "SAA"
 }
]

我将 2 个 Json 数组转换为键值对映射,其中 EmployeeId 作为数组 1 中的键,Emp_id 作为数组 2 中的键。当我比较 2 个映射时,映射中的值顺序不同并且失败了。

如何比较 2 个 API 以确保 2 个 api 中每个元素的值匹配。

【问题讨论】:

  • 您可能需要逐个比较属性
  • 由于只有一组数据,现在一个接一个就可以了。我也有返回与多个员工 ID 对应的数据的 API。
  • 不要将它们与 Json 数组进行比较。将它们与Map 进行比较。

标签: java arrays json collections


【解决方案1】:

首先,您需要创建一个模型来表示这两个JSON 有效负载。它们几乎相似,除了 Zip 键的键名和值,在第一个有效负载中它是第二个数字原语 - String 原语。日期也有不同的格式,因此您需要通过实现自定义日期反序列化器来处理它们。

绝对应该使用JacksonGson 库,它允许将JSON 反序列化为POJO 模型,提供自定义日期反序列化器,以及任何其他许多功能。

以下示例提供示例解决方案:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;

import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Objects;

public class GsonApp {

    public static void main(String[] args) throws Exception {
        File jsonApi1 = new File("./resource/test.json").getAbsoluteFile();
        File jsonApi2 = new File("./resource/test1.json").getAbsoluteFile();

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
                    private final SimpleDateFormat formatWithTimeZoneIndicator = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SS");
                    private final SimpleDateFormat formatWithoutTimeZoneIndicator = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SS");

                    @Override
                    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                        String date = json.getAsString();
                        try {
                            return formatWithoutTimeZoneIndicator.parse(date);
                        } catch (ParseException e) {
                            try {
                                return formatWithTimeZoneIndicator.parse(date);
                            } catch (ParseException e1) {
                                throw new JsonParseException(e1);
                            }
                        }
                    }
                })
                .create();

        Type employeesType = new TypeToken<List<Employee>>() {}.getType();
        try (FileReader readerApi1 = new FileReader(jsonApi1);
             FileReader readerApi2 = new FileReader(jsonApi2)) {
            List<Employee> employees1 = gson.fromJson(readerApi1, employeesType);
            List<Employee> employees2 = gson.fromJson(readerApi2, employeesType);

            System.out.println(employees1);
            System.out.println(employees2);
            System.out.println(employees1.equals(employees2));
        }
    }
}

class Employee {

    @SerializedName(value = "employeeSalutation", alternate = {"emp_Sal"})
    private String employeeSalutation;

    @SerializedName(value = "EmployeeName", alternate = {"Emp_Name"})
    private String employeeName;

    @SerializedName(value = "EmployeeCode", alternate = {"Emp_Code"})
    private String employeeCode;

    @SerializedName("Zip")
    private JsonPrimitive zip;

    @SerializedName(value = "DepartmentName", alternate = {"Dept_Name"})
    private String departmentName;

    @SerializedName(value = "EmployeeAddress", alternate = {"Emp_addr"})
    private String employeeAddress;

    @SerializedName(value = "StateCode", alternate = {"Stat_cd"})
    private int stateCode;

    @SerializedName(value = "updatedDate", alternate = {"upd_d"})
    private Date updatedDate;

    @SerializedName(value = "EmployeeId", alternate = {"Emp_id"})
    private int employeeId;

    public String getEmployeeSalutation() {
        return employeeSalutation;
    }

    public void setEmployeeSalutation(String employeeSalutation) {
        this.employeeSalutation = employeeSalutation;
    }

    public String getEmployeeName() {
        return employeeName;
    }

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }

    public String getEmployeeCode() {
        return employeeCode;
    }

    public void setEmployeeCode(String employeeCode) {
        this.employeeCode = employeeCode;
    }

    public JsonPrimitive getZip() {
        return zip;
    }

    public void setZip(JsonPrimitive zip) {
        this.zip = zip;
    }

    public String getDepartmentName() {
        return departmentName;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    public String getEmployeeAddress() {
        return employeeAddress;
    }

    public void setEmployeeAddress(String employeeAddress) {
        this.employeeAddress = employeeAddress;
    }

    public int getStateCode() {
        return stateCode;
    }

    public void setStateCode(int stateCode) {
        this.stateCode = stateCode;
    }

    public Date getUpdatedDate() {
        return updatedDate;
    }

    public void setUpdatedDate(Date updatedDate) {
        this.updatedDate = updatedDate;
    }

    public int getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(int employeeId) {
        this.employeeId = employeeId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return stateCode == employee.stateCode &&
                employeeId == employee.employeeId &&
                Objects.equals(employeeSalutation, employee.employeeSalutation) &&
                Objects.equals(employeeName, employee.employeeName) &&
                Objects.equals(employeeCode, employee.employeeCode) &&
                Objects.equals(zip.getAsString(), employee.zip.getAsString()) &&
                Objects.equals(departmentName, employee.departmentName) &&
                Objects.equals(employeeAddress, employee.employeeAddress) &&
                Objects.equals(updatedDate, employee.updatedDate);
    }

    @Override
    public int hashCode() {
        return Objects.hash(employeeSalutation, employeeName, employeeCode, zip, departmentName, employeeAddress, stateCode, updatedDate, employeeId);
    }

    @Override
    public String toString() {
        return "Employee{" +
                "employeeSalutation='" + employeeSalutation + '\'' +
                ", employeeName='" + employeeName + '\'' +
                ", employeeCode='" + employeeCode + '\'' +
                ", zip=" + zip +
                ", departmentName='" + departmentName + '\'' +
                ", employeeAddress='" + employeeAddress + '\'' +
                ", stateCode=" + stateCode +
                ", updatedDate='" + updatedDate + '\'' +
                ", employeeId=" + employeeId +
                '}';
    }
}

上面的代码打印:

[Employee{employeeSalutation='null', employeeName='Example', employeeCode='SAA', zip=12345, departmentName='Social science', employeeAddress='123 st', stateCode=9, updatedDate='Mon Jan 22 03:48:43 CET 2018', employeeId=1257}]
[Employee{employeeSalutation='null', employeeName='Example', employeeCode='SAA', zip="12345", departmentName='Social science', employeeAddress='123 st', stateCode=9, updatedDate='Mon Jan 22 03:48:43 CET 2018', employeeId=1257}]
true

【讨论】:

  • 顺便说一句,如果你使用Jackson,你可以使用@JsonAlias(从2.9.0开始)进行反序列化。
【解决方案2】:

JSONAssertlibrairy 对于此类任务非常方便。

这里是good tutorial关于如何使用它。

希望对你有帮助。

【讨论】:

    【解决方案3】:

    由于您在 Java 中执行此操作,我建议您将此值映射到 Java 对象中。 这样,您就可以非常轻松地比较值。你可以使用像 Gson 这样的库,但在这里我将向你展示如何在没有库的情况下做到这一点。

    创建一个易于用于您的 API 响应的类:

    public class Employee {
    
     private String employeeSalutation; //i am not sure what type should this variable be
     private String employeeName;
     private String employeeCode;
     private int zip;
     private String departmentName;
     private String employeeAddress;
     private int stateCode;
     private String updatedDate;
     private int employeeId;
    
     //this is where your parser can be used
     public Employee(String employeeSalutation, String employeeName, String employeeCode, 
       int zip, String departmentName, String employeeAddress, int stateCode,String updatedDate, int employeeId){
         this.employeeSalutation = employeeSalutation;
         this.employeeName = employeeName;
         this.employeeCode = employeeCode;
         this.zip = zip;
         this.departmentName = departmentName;
         this.employeeAddress = employeeAddress;
         this.stateCode = stateCode;
         this.updatedDate = updatedDate;
         this.employeeId = employeeId; 
     }
    //getters, setters 
    }
    

    现在你可以有一个类,用于将这些数组转换为 Java 对象,我们称之为 EmployeeConverter:

    public class EmployeeConverter { 
    
      public Employee convertApi1Employee(String json){
      //since you didn't clarify how are you accessing your Json values, i will now use pseudo-code to finish my answer.
    
        //using variable.value pseudo-code to access json property value
        return new Employee(employeeSalutation.value, EmployeeName.value, EmployeeCode.value, Zip.value, DepartmentName.value, EmployeeAddress.value, EmployeeAddress.value, StateCode.value, updatedDate.value, EmployeeId.value);        
      }
    } 
    

    您应该创建方法 convertApi2Employee(),它具有与 convertApi1Employee() 方法完全相同的功能,但将使用不同的 JSON 对象。

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2011-12-27
      • 2014-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-07
      • 2014-11-20
      • 1970-01-01
      相关资源
      最近更新 更多