I made it because I wanted to compare beans with JUnit.
Fixed a bug that an infinite loop occurs when the equals method is implemented with this.
When throws, the caller is Mendokusai, so I modified it to catch internally.
For classes under java.lang ⇒ Call the native equals method. Compare toStrings if equals method is not implemented
If it is not under java.lang and it is an array ⇒ Check the length and each element
If it is not under java.lang and it is not an array ⇒ Check the value of the field
/**
 *Convenient equals method
 *OK even if the equals method is not implemented.I'll also check the superclass fields.
 * @param a
 * @param b
 * @return
 */
@SuppressWarnings("unchecked")
public static boolean reflectEquals( Object a, Object b ){
        try{
        if (a == b) {
            return true;
        }
        if (a == null || b == null ) {
            return a == b;
        }
        if (a.getClass() != b.getClass()) {
            return false;
        }
        boolean useBuildinEqualsFlg = a.getClass().getName().startsWith("java.lang");
        if( useBuildinEqualsFlg ){
            try{
                Method equalsMethod = a.getClass().getDeclaredMethod("equals", Object.class);
                boolean eqFlg = Boolean.class.cast( equalsMethod.invoke(a, b) );
                return eqFlg;
            }catch( NoSuchMethodException e ) {
                String aStr = a.toString();
                String bStr = b.toString();
                boolean eqFlg = aStr.equals(bStr);
                return eqFlg;
            }
        }else{
            if( a instanceof List ) {
                a = ((List<Object>) a).toArray();
                b = ((List<Object>) b).toArray();
            }
            if( a.getClass().isArray() ) {
                int aLen = Array.getLength(a);
                int bLen = Array.getLength(b);
                if( aLen != bLen ) {
                    return false;
                }
                for( int i = 0;i<aLen;i++) {
                    Object aElement= Array.get(a, i);
                    Object bElement= Array.get(b, i);
                    if( !reflectEquals( aElement, bElement ) ) {
                        return false;
                    }
                }
                return true;
            }
            List<Field> fields = getAllFields(a.getClass());
            for( Field field : fields ) {
                field.setAccessible(true);
                Object aFieldObj = field.get(a);
                Object bFieldObj = field.get(b);
                boolean eqFlg = reflectEquals( aFieldObj, bFieldObj);
                if( !eqFlg ) {
                    return false;
                }
            }
            return true;
        }
    }catch(IllegalAccessException | IllegalArgumentException | SecurityException | InvocationTargetException e ){
        throw new RuntimeException(e);
    }
}
/**
 *Superclass also goes back and gets all fields
 * @param clazz
 * @return
 */
private static List<Field> getAllFields(Class<?> clazz){
	List<Field> allFields = new ArrayList<>();
	if( clazz != Object.class ) {
		Field[] fields = clazz.getDeclaredFields();
		allFields.addAll( Arrays.asList(fields) );
		allFields.addAll( getAllFields(clazz.getSuperclass()) );
	}
	return allFields;
}
↓ Call like this.
reflectEquals(obj1, obj2)
After making a masterpiece, I realized that this is all I need to do ...
Gson gson = new GsonBuilder().setPrettyPrinting().create();
gson.toJson(obj1).equals( gson.toJson(obj2) );
        Recommended Posts