Java Bean/100フィールドのエンティティ(この場合は継承されているかどうかは関係ありません)があるとします)更新操作後-トランザクションで、どのフィールドが変更されているかを確認したいCVSのような更新を追跡するため。これを行う最も簡単な方法は何ですか?フレームワークの提案はありますか?このオブジェクトの2つのインスタンスを作成し、すべてのフィールドを繰り返してフィールドの値を一致させる必要がありますか?そのような状況で最良のequalsメソッドはどのように見えますか? ?次のequals()は非常に扱いにくいようです:
return (field1.equals(o.field1)) &&
(field2.equals(o.field2)) &&
(field3.equals(o.field3)) &&
...
(field100.equals(o.field100));
Apache CommonsBeanutilsを使用できます。簡単な例を次に示します。
package at.percom.temp.zztests;
import Java.lang.reflect.InvocationTargetException;
import org.Apache.commons.beanutils.BeanMap;
import org.Apache.commons.beanutils.PropertyUtilsBean;
import Java.util.Arrays;
import Java.util.HashSet;
import Java.util.Objects;
import Java.util.Set;
public class Main {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
Main main = new Main();
main.start();
}
public void start() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
SampleBean oldSample = new SampleBean("John", "Doe", 1971);
SampleBean newSample = new SampleBean("John X.", "Doe", 1971);
SampleBean diffSample = (SampleBean) compareObjects(oldSample, newSample, new HashSet<>(Arrays.asList("lastName")), 10L);
}
public Object compareObjects(Object oldObject, Object newObject, Set<String> propertyNamesToAvoid, Long deep) {
return compareObjects(oldObject, newObject, propertyNamesToAvoid, deep, null);
}
private Object compareObjects(Object oldObject, Object newObject, Set<String> propertyNamesToAvoid, Long deep,
String parentPropertyPath) {
propertyNamesToAvoid = propertyNamesToAvoid != null ? propertyNamesToAvoid : new HashSet<>();
parentPropertyPath = parentPropertyPath != null ? parentPropertyPath : "";
Object diffObject = null;
try {
diffObject = oldObject.getClass().newInstance();
} catch (Exception e) {
return diffObject;
}
BeanMap map = new BeanMap(oldObject);
PropertyUtilsBean propUtils = new PropertyUtilsBean();
for (Object propNameObject : map.keySet()) {
String propertyName = (String) propNameObject;
String propertyPath = parentPropertyPath + propertyName;
if (!propUtils.isWriteable(diffObject, propertyName) || !propUtils.isReadable(newObject, propertyName)
|| propertyNamesToAvoid.contains(propertyPath)) {
continue;
}
Object property1 = null;
try {
property1 = propUtils.getProperty(oldObject, propertyName);
} catch (Exception e) {
}
Object property2 = null;
try {
property2 = propUtils.getProperty(newObject, propertyName);
} catch (Exception e) {
}
try {
if (property1 != null && property2 != null && property1.getClass().getName().startsWith("com.racing.company")
&& (deep == null || deep > 0)) {
Object diffProperty = compareObjects(property1, property2, propertyNamesToAvoid,
deep != null ? deep - 1 : null, propertyPath + ".");
propUtils.setProperty(diffObject, propertyName, diffProperty);
} else {
if (!Objects.deepEquals(property1, property2)) {
propUtils.setProperty(diffObject, propertyName, property2);
System.out.println("> " + propertyPath + " is different (oldValue=\"" + property1 + "\", newValue=\""
+ property2 + "\")");
} else {
System.out.println(" " + propertyPath + " is equal");
}
}
} catch (Exception e) {
}
}
return diffObject;
}
public class SampleBean {
public String firstName;
public String lastName;
public int yearOfBirth;
public SampleBean(String firstName, String lastName, int yearOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.yearOfBirth = yearOfBirth;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getYearOfBirth() {
return yearOfBirth;
}
}
}
ちょっと見てください Javers それはまさにあなたが必要とするものです-オブジェクト監査と差分フレームワーク。 Javersを使用すると、更新のたびに1回のjavers.commit()
呼び出しで、ドメインオブジェクトに対して行われた変更を永続化できます。いくつかの変更を永続化する場合、javers.getChangeHistory
で簡単に読み取ることができます。
public static void main(String... args) {
//get Javers instance
Javers javers = JaversBuilder.javers().build();
//create Java bean
User user = new User(1, "John");
//commit current state
javers.commit("author", user);
//update operation
user.setUserName("David");
//commit change
javers.commit("author", user);
//read 100 last changes
List<Change> changes = javers.getChangeHistory(instanceId(1, User.class), 100);
//print change log
System.out.printf(javers.processChangeList(changes, new SimpleTextChangeLog()));
}
出力は次のとおりです。
commit 2.0, author:author, 2015-01-07 23:00:10
changed object: org.javers.demo.User/1
value changed on 'userName' property: 'John' -> 'David'
commit 1.0, author:author, 2015-01-07 23:00:10
new object: 'org.javers.demo.User/1
リフレクションを使用してフィールドをロードし、各オブジェクトでそれらを呼び出して結果を比較できます。
ソースコードの例は次のようになります。
public static <T> void Compare(T source, T target) throws IllegalArgumentException, IllegalAccessException {
if(source == null) {
throw new IllegalArgumentException("Null argument not excepted at this point");
}
Field[] fields = source.getClass().getFields();
Object sourceObject;
Object targetObject;
for(Field field : fields){
sourceObject = field.get(source);
targetObject = field.get(target);
//Compare the object
}
}
参考までに、このコードはクラス用に宣言されたパブリックフィールドでのみ機能します。
Apache BeanUtils を使用してプロパティをチェックアウトできます。