According to your requirement you can do this as follow.
you can take two database rows to two objects. Eg: SampleObject
public class SampleObject {
private String name;
private int age;
private String email;
public SampleObject(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
.
.
I imagine your results will be an object too. Eg : ResultObject
public class ResultObject {
private String fieldName;
private String OldObjectValue;
private String NewObjectValue;
.
.
You can just define a compareField kind of method in SampleObject
public List<ResultObject> compareFields(SampleObject object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{
List<ResultObject> resultList = new ArrayList<ResultObject>();
Field[] fields = this.getClass().getDeclaredFields();
for(Field field : fields){
if(!field.get(this).equals(field.get(object))){
ResultObject resultObject = new ResultObject();
resultObject.setFieldName(field.getName());
resultObject.setOldObjectValue(field.get(this).toString());
resultObject.setNewObjectValue(field.get(object).toString());
resultList.add(resultObject);
}
}
return resultList;
}
Then you can make it work.
SampleObject object1 = new SampleObject("ABC", 29, "[email protected]");
SampleObject object2 = new SampleObject("XYZ", 29, "[email protected]");
List<ResultObject> resultList = object1.compareFields(object2);
Thanks
Answer from isurujay on Stack Overflowcompare two objects
java - how to compare two objects and find the fields/properties changed? - Stack Overflow
java - How to compare two objects and get the changed fields - Stack Overflow
Optimal way to compare two objects of the same type
Videos
With Java 8:
Comparator.comparing((Person p)->p.firstName)
.thenComparing(p->p.lastName)
.thenComparingInt(p->p.age);
If you have accessor methods:
Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName)
.thenComparingInt(Person::getAge);
If a class implements Comparable then such comparator may be used in compareTo method:
@Override
public int compareTo(Person o){
return Comparator.comparing(Person::getFirstName)
.thenComparing(Person::getLastName)
.thenComparingInt(Person::getAge)
.compare(this, o);
}
You should implement Comparable <Person>. Assuming all fields will not be null (for simplicity sake), that age is an int, and compare ranking is first, last, age, the compareTo method is quite simple:
public int compareTo(Person other) {
int i = firstName.compareTo(other.firstName);
if (i != 0) return i;
i = lastName.compareTo(other.lastName);
if (i != 0) return i;
return Integer.compare(age, other.age);
}
I have two objects that I need to compare if they are equal. They will only contain JS primitives and JS Date objects.
object a
{
first_name: "Fred",
last_name: "Flintstone",
modified_datetime: 2022-09-01Z00:00:00,
age: 42,
has_children: true,
living_the_life: "maybe",
}
object b
{
firstName: "Fred",
lastName: "Flintstone",
modified: 2022-09-01Z00:00:00,
yearsAlive: 42,
hasChildren: true,
living_the_life: "i don't care about this field",
}I would like to compare these two object. The field names are similar, but will not always follow a convention (ie make snake case = camel case). Some fields like age => yearsAlive have completely different names... other fields like living_the_life are completely ignored. My first inclination is just a Map() object to map fields from object a to object b. Run through the keys of that map checking for equality. It's plausible a field like age maybe be passed in as a number or string... I think using == makes sense ... but would prefer === and force those send data to send the appropriate data type. Is there a clever library or even lodash function that already has this functionality? Or just build it myself? In this case object a = object b.
I think this is the method you searching for:
private static List<String> difference(Student s1, Student s2) throws IllegalAccessException {
List<String> changedProperties = new ArrayList<>();
for (Field field : s1.getClass().getDeclaredFields()) {
// You might want to set modifier to public first (if it is not public yet)
field.setAccessible(true);
Object value1 = field.get(s1);
Object value2 = field.get(s2);
if (value1 != null && value2 != null) {
System.out.println(field.getName() + "=" + value1);
System.out.println(field.getName() + "=" + value2);
if (!Objects.equals(value1, value2)) {
changedProperties.add(field.getName());
}
}
}
return changedProperties;
}
This is an enhancement of Dumbo's difference method, using recursion to check all nested complex fields.
private static void difference(Object s1, Object s2, List<String> changedProperties, String parent) throws IllegalAccessException {
for (Field field : s1.getClass().getDeclaredFields()) {
if (parent == null) {
parent = s1.getClass().getSimpleName();
}
field.setAccessible(true);
Object value1 = field.get(s1);
Object value2 = field.get(s2);
if (value1 == null && value2 == null) {
continue;
}
if (value1 == null || value2 == null) {
changedProperties.add(parent + "." + field.getName());
} else {
if (isBaseType(value1.getClass())) {
if (!Objects.equals(value1, value2)) {
changedProperties.add(parent + "." + field.getName());
}
} else {
difference(value1, value2, changedProperties, parent + "." + field.getName());
}
}
}
}
private static final Set<Class> BASE_TYPES = new HashSet(Arrays.asList(
String.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class));
public static boolean isBaseType(Class clazz) {
return BASE_TYPES.contains(clazz);
}
Sample usage (assumes the referenced model objects have getters/setters):
public static void main(String[] args) throws IllegalAccessException {
Student s1 = new Student();
s1.setName("Krishna");
s1.setAge(30);
Address address = new Address();
s1.setAddress(address);
s1.getAddress().setHno("2-2-22");
s1.getAddress().setStreet("somewhere");
s1.getAddress().setPin(123);
Student s2 = new Student();
s2.setName("Krishna");
s2.setAge(20);
address = new Address();
s2.setAddress(address);
s2.getAddress().setHno("1-1-11");
s2.getAddress().setStreet("nowhere");
s2.getAddress().setPin(123);
List<String> changedProperties = new ArrayList<>();
difference(s1, s2, changedProperties, null);
System.out.println("changedProperties = " + changedProperties);
// expected result
// Student.age
// Student.address.hno
// Student.address.street
}
Result:
changedProperties = [Student.address.hno, Student.address.street, Student.age]
Primitive adapting checking adapted from https://stackoverflow.com/a/711226/1527469
Well i found a solution as below :
private static List<String> getDifference(Object s1, Object s2) throws IllegalAccessException {
List<String> values = new ArrayList<>();
for (Field field : s1.getClass().getDeclaredFields()) {
field.setAccessible(true);
Object value1 = field.get(s1);
Object value2 = field.get(s2);
if (value1 != null && value2 != null) {
if (!Objects.equals(value1, value2)) {
values.add(String.valueOf(field.getName()+": "+value1+" -> "+value2));
}
}
}
return values;
}
You may use javers library for this.
<groupId>org.javers</groupId>
<artifactId>javers-core</artifactId>
POJO:
public class Person {
private Integer id;
private String name;
// standard getters/constructors
}
Usage:
@Test
public void givenPersonObject_whenApplyModificationOnIt_thenShouldDetectChange() {
// given
Javers javers = JaversBuilder.javers().build();
Person person = new Person(1, "Michael Program");
Person personAfterModification = new Person(1, "Michael Java");
// when
Diff diff = javers.compare(person, personAfterModification);
// then
ValueChange change = diff.getChangesByType(ValueChange.class).get(0);
assertThat(diff.getChanges()).hasSize(1);
assertThat(change.getPropertyName()).isEqualTo("name");
assertThat(change.getLeft()).isEqualTo("Michael Program");
assertThat(change.getRight()).isEqualTo("Michael Java");
}
Plus other use cases are supported as well.
To give some background, I need to compare a List of a certain Entity from my DB to a List of that same entity type from an External API. Both lists are going to be mapped to the same DTO Record so they will be identical. The DTO is linked by a common ExternalID, after having both matching DTOs, I need to check if any of the field values are different between two objects (Id and ExternalId don't need to be compared). Below is the DTO I will be doing the comparison on.
public record TestDto
{
public Guid Id { get; set; }
public int? ExternalId { get; set; }
public string? Name { get; set; }
public string? EventType { get; set; }
public int? TicketQuantity { get; set; }
public float? TotalTicketCost { get; set; }
public int? ListingCount { get; set; }
public int? ExternalCategoryId { get; set; }
public string? ExternalCategoryName { get; set; }
}I know multiple ways I can do this however they are far from optimal. I am looking for the most optimal way to go about it since I will need to do this for 5K+ records.
this code is giving me False
class compare:
def __init__(self, val, next=None):
self.val = val
self.next = next
a = compare(1)
b = compare(1)
c = compare(2)
a.next = c
b.next = c
print(a == b)in this example, I can do
print(a.val == b.val and a.next == b.next)
but what about the complex objects? How to compare if every attribute is of same value?
The “different member variables” is irrelevant. It’s an implementation detail. What you need is a set of rules which of two people comes first.
You could for example sort by family name, then given name, then date of birth, and if these are all three equal, take the name of the school, university or company (which will be different member variables) and compare them as strings. If that is equal, you might have student and employee ids, and the student ids might be unique, and the employee ids might be unique, but student and employee ids might be the same. So you could sort then students first ordered by id, followed by employees sorted by id, if you might sort by if first if student and employee ids are comparable.
(University or school and employer might be the same, because universities are also employers).
Comparing objects with different fields sounds like bad polymorphic design, whether it's Java or any other OOP language:
- If your comparator needs to know the precise subtype of an object to do the comparison, you mess-up with the the open-closed principle, since for every new subclassing, you'd potentially need to modify the comparator to select the relevant fields.
- If your comparator needs uses reflexion to find on its own the relevant fields to compare, you indirectly mess up with the principle of encapsulation, since you create a hidden requirement that information to be compared must be in some predetermined field.
If you want to sort People properly in a clean polymorphic design:
- you need to rely either on a field, available for any kind of
People, includingStudent, or - you may call some function/transformation that provides a unique value (e.g. a string) that allows to sort any
People.PeopleandStudentmay then just use a different transformation that will be passed to the comparator; Or - you only sort among homogeneous subtypes.