Java General-purpose method that retrieves only the differences between the properties of objects of the same class

Introduction

It's like String.equals ("A", "B"), there are comparisons between objects, but `How do you compare the properties in an object and extract the parts that differ? `` I looked it up.

What I want to do is when there is an object like the one below (I thought it would be easy to explain the contents of the object in json, so I expressed it in json. The language used is Java)

//object1
{
  "id":1,
 "name": "Original",
 "description": "same",
}

//object2
{
  "id":2,
 "name": "is a clone",
 "description": "same",
}

Compare the properties of ʻObject1 and ʻObject2 in this pattern, I want the following one that outputs only the properties that differ.

 //以下のような例で比較できて,
CompareHelper.diff(Object1,Object2);

 //出力はこんな感じにしてくれるやつ
{
  "id":2,
 "name": "is a clone",
}

Reference site

Here is what I wanted to do when I looked it up myself. https://ocs.hatenadiary.org/entry/20101204/1291396815

ObjectUtils.equal(aPropValue, bPropValue) Was deprecated, so ObjectUtils.notEqual(aPropValue, bPropValue) I'd like you to refer to the usage example.

Is as per the reference site and uses the library.

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import lombok.Data;

public class CompareHelper {

    public static <T> List<Difference> diff(T a, T b) {
        BeanWrapper aWrap = new BeanWrapperImpl(a);
        PropertyDescriptor[] pds = aWrap.getPropertyDescriptors();
        List<String> propertyNames = new ArrayList<String>();
        for (PropertyDescriptor pd : pds) {
            if (aWrap.isReadableProperty(pd.getName())) {
                propertyNames.add(pd.getName());
            }
        }

        BeanWrapper bWrap = new BeanWrapperImpl(b);
        List<Difference> differences = new ArrayList<Difference>();

        for (String propertyName : propertyNames) {
            Object aPropValue = aWrap.getPropertyValue(propertyName);
            Object bPropValue = bWrap.getPropertyValue(propertyName);
            if (ObjectUtils.notEqual(aPropValue, bPropValue)) {
                Difference d = new Difference();
                d.setPropertyName(propertyName);
                d.setLeft(aPropValue);
                d.setRight(bPropValue);
                differences.add(d);
            }
        }

        return differences;
    }

    @Data
    public static class Difference {
        private String propertyName;
        private Object left;
        private Object right;
    }
}

When to use

When using it, it looks like the following You can compare the same objects and retrieve the different property names and their values.

I wonder if the scene used as a Spring user looks like this. .. ..


 //比較するオブジェクトの例として,よくあるユーザエンティティを使用してみました
@Entity
public class User implements Cloneable {

 // Object # clone is protected and cannot be called by default.
 // Override the clone method
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String description;
}


 //上記のようなユーザのエンティティ同士を比較します.
public void main(){
 //オリジナルのオブジェクトは,こんな感じで取得していたとする.
 // The original name is "Before renaming".
    User original = userService.findByUserName("original");

 //オリジナルのクローンを作成
    User clone = original.clone();    

 //オリジナルの名前に変更があった
 original.setName ("renamed");

 //オリジナルとクローンを比較
    List<Difference> diffList = CompareHelper.diff(clone, original);
    for (Difference diff : diffList) {
        System.out.println( diff.getPropertyName() + " : " + diff.getLeft() + " -> " + 
     diff.getRight() );
    }    
}

 // The output looks like this
 //> name: Before renaming-> Renamed

Miscellaneous feelings

Explanation of the comparison method itself when examined lightly (Explanation of common addictive points such as using ʻequals, == and === `) I couldn't get to the place I wanted to do because a site to do it came out.

Is there a utility that can do similar things in other languages, frameworks, and libraries in the first place?

This time I studied based on the reference site, To get the difference between properties without using the library and keeping the basic language specifications ... Is there no choice but to create the diff method for each class on its own?

If you know, please let me know!

Recommended Posts

Java General-purpose method that retrieves only the differences between the properties of objects of the same class
[Java] Wrapper that executes private method of object from outside class
Output the difference between each field of two objects in Java
[Java] Differences between instance variables and class variables
Differences between Java, C # and JavaScript (how to determine the degree of obesity)
Increment with the third argument of iterate method of Stream class added from Java9
[Java] Where is the implementation class of annotation that exists in Bean Validation?
[Java] Handling of JavaBeans in the method chain
About the description order of Java system properties
Import files of the same hierarchy in Java
General-purpose StringConverter class that utilizes generics in Java8
First touch of the Files class (or Java 8)
ArchUnit practice: Enforce package private visibility of classes that depend only on the same package
[Java] How to use compareTo method of Date class
Browse class objects in Kotlin (instead of Java class name.class)
Summarize the additional elements of the Optional class in Java 9
Replace only part of the URL host with java