JUnitでBean同士の比較をしたくて作ってしまいました。
※equalsメソッドをこれで実装すると無限ループになってしまうバグを修正しました。
※throwsすると呼び出し側がメンドクサイので、内部でcatchへ修正しました。
- java.lang配下のクラスの場合 ⇒ ネイティブのequalsメソッドを呼び出す。equalsメソッド未実装だったらtoString同士を比較
- java.lang配下じゃない、かつ配列の場合 ⇒ 長さ、各要素のチェック
- java.lang配下じゃない、かつ配列じゃない場合 ⇒ フィールドの値をチェック
/**
* 便利なequalsメソッド
* equalsメソッドが実装されてなくてもOK.スーパークラスのフィールドもチェックするよ.
* @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);
}
}
/**
* スーパークラスも遡って全てのフィールドを取得する
* @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;
}
↓こうやって呼び出す。
reflectEquals(obj1, obj2)
と力作作った後にこれだけ↓で済むことに気づいた…
Gson gson = new GsonBuilder().setPrettyPrinting().create();
gson.toJson(obj1).equals( gson.toJson(obj2) );