Java 仅基于公共属性动态比较两个不同类的对象
我正在编写一些完全动态的方法,其中需要比较不同类的两个对象 以下是对象的示例:Java 仅基于公共属性动态比较两个不同类的对象,java,reflection,Java,Reflection,我正在编写一些完全动态的方法,其中需要比较不同类的两个对象 以下是对象的示例: public class Object1 { private String lastname; private String firstname; private int age; private int gender; //All getters and setters } public class Object2 { private String lastn
public class Object1 {
private String lastname;
private String firstname;
private int age;
private int gender;
//All getters and setters
}
public class Object2 {
private String lastname;
private String address;
private String job;
//All getters and setters
}
正如您在这里看到的,惟一的公共属性是lastname,因此我希望我的比较只适用于lastname
此外:
- 在我的实际代码中,我使用了很多不同的类,我不能让它们实现公共接口,事实上,我根本不能修改它们
- 我不知道哪些可能是commons属性,所以我不能硬编码我的测试
- 我正在使用Java8
public interface sampleEndpoint<BEANPARAM,BODYREQUEST,RESPONSE> {
@PUT
@Path("/{id}")
default RESPONSE update(@Valid @BeanParam BEANPARAM bp, @Valid BODYREQUEST body) {
//Check if id in path is the same as id in the body
....
}
}
公共接口采样端点{
@放
@路径(“/{id}”)
默认响应更新(@Valid@BeanParam-BeanParam-bp,@Valid-BODYREQUEST-body){
//检查路径中的id是否与主体中的id相同
....
}
}
(对于Jersey,我们不能在同一个Bean PathParam、QueryParam和RequestBody中使用BeanParam进行检索……这就是为什么我需要同时使用BeanParam和另一个Bean作为主体的原因)
我的用例可能更复杂,但这是一个简单的例子。从我收集的信息来看,它似乎正是您所寻找的。您可以获得每个类中所有字段的列表,然后仅当两个字段的名称相同时才比较它们的值
这种方法的主要好处是,它可以推广到任何两个类。然而,反射经常被反对,因为它破坏了封装,我建议您在解决这个问题之前,针对您的问题寻找更好的解决方案。从我收集的信息来看,反射似乎正是您所寻找的。您可以获得每个类中所有字段的列表,然后仅当两个字段的名称相同时才比较它们的值
这种方法的主要好处是,它可以推广到任何两个类。然而,反射经常被反对,因为它破坏了封装,我建议您在解决这个问题之前,针对您的问题寻找更好的解决方案。我最终创建了自己的类来实现我想要的 我决定使用jackson(fasterxml)转换JsonNode中的对象,然后递归地比较JsonNodes 下面是代码(我需要做一些测试来更深入地验证它,但它适用于我的用例):
import com.fasterxml.jackson.databind.JsonNode;
导入com.fasterxml.jackson.databind.ObjectMapper;
导入java.util.Iterator;
公共类对象比较器{
/**
*对于«预期»对象的每个属性,验证该属性是否存在于«实际»中,如果存在,验证该值是否与«预期»值相同
*
*@param应为:引用JsonNode
*@param-actual:我们要在其中验证属性的对象
*@如果«预期»和«实际»之间的所有公共属性具有相同的值,则返回true,否则返回false
*/
公共静态布尔CommonAttributesComparator(预期对象,实际对象){
ObjectMapper mapper=新的ObjectMapper();
JsonNode expectedNode=mapper.convertValue(应为JsonNode.class);
JsonNode actualNode=mapper.convertValue(实际,JsonNode.class);
返回(JsonNodeComparator(expectedNode,actualNode));
}
/**
*对于«预期»JsonNode的每个属性,验证该属性是否存在于«实际»中,如果存在,验证该值是否与«预期»值相同
*
*@param expectedNode:引用JsonNode
*@param actualNode:我们要在其中验证属性的JsonNode
*@如果«预期»和«实际»之间的所有公共属性具有相同的值,则返回true,否则返回false
*/
公共静态布尔JsonNodeComparator(JsonNode expectedNode,JsonNode actualNode){
迭代器expectedKeys=expectedNode.fieldNames();
如果(!expectedKeys.hasNext()){
返回expectedNode.equals(实际节点);
}
while(expectedKeys.hasNext()){
字符串currentKey=expectedKeys.next();
如果(
!expectedNode.get(currentKey).isNull()
&&actualNode.has(currentKey)
&&!actualNode.get(currentKey.isNull()){
if(expectedNode.get(currentKey.isArray()){
if(actualNode.get(currentKey).isArray()
&&actualNode.get(currentKey).size()==expectedNode.get(currentKey).size()){
布尔子节点comparisonsucceeed=false;
for(最终JsonNode expectedSubNode:expectedNode.get(currentKey)){
for(最终JsonNode actualSubNode:actualNode.get(currentKey)){
SubNodeComparisonSuccessed=JSONNodeCompariator(expectedSubNode,actualSubNode);
如果(子节点比较已成功){
打破
}
}
如果(!SubNodeComparisonSuccessed){
返回false;
}
}
}else if(expectedNode.get(currentKey).size()>0){
返回false;
}
}埃尔
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Iterator;
public class ObjectComparator {
/**
* For each attribute of «expected» Object, verify if this attribute exists in «actual» and if it exists, verify if the value is the same as the «expected» one
*
* @param expected : the reference JsonNode
* @param actual : the Object in which we want to verify the attributes
* @return true if all commons attributes between «expected» and «actual» have same values, otherwise returns false
*/
public static boolean CommonsAttributesComparator(Object expected, Object actual) {
ObjectMapper mapper = new ObjectMapper();
JsonNode expectedNode = mapper.convertValue(expected, JsonNode.class);
JsonNode actualNode = mapper.convertValue(actual, JsonNode.class);
return(JsonNodeComparator(expectedNode, actualNode));
}
/**
* For each attribute of «expected» JsonNode, verify if this attribute exists in «actual» and if it exists, verify if the value is the same as the «expected» one
*
* @param expectedNode : the reference JsonNode
* @param actualNode : the JsonNode in which we want to verify the attributes
* @return true if all commons attributes between «expected» and «actual» have same values, otherwise returns false
*/
public static boolean JsonNodeComparator(JsonNode expectedNode, JsonNode actualNode) {
Iterator<String> expectedKeys = expectedNode.fieldNames();
if(!expectedKeys.hasNext()) {
return expectedNode.equals(actualNode);
}
while (expectedKeys.hasNext()) {
String currentKey = expectedKeys.next();
if (
!expectedNode.get(currentKey).isNull()
&& actualNode.has(currentKey)
&& !actualNode.get(currentKey).isNull()) {
if (expectedNode.get(currentKey).isArray()) {
if (actualNode.get(currentKey).isArray()
&& actualNode.get(currentKey).size() == expectedNode.get(currentKey).size()) {
boolean subNodeComparisonSucceeded = false;
for (final JsonNode expectedSubNode : expectedNode.get(currentKey)) {
for (final JsonNode actualSubNode : actualNode.get(currentKey)) {
subNodeComparisonSucceeded = JsonNodeComparator(expectedSubNode, actualSubNode);
if(subNodeComparisonSucceeded) {
break;
}
}
if(!subNodeComparisonSucceeded) {
return false;
}
}
} else if(expectedNode.get(currentKey).size() > 0) {
return false;
}
} else if(!expectedNode.get(currentKey).equals(actualNode.get(currentKey))) {
return false;
}
}
}
return true;
}
}