r2198 - in trunk/nuiton-utils/src: main/java/org/nuiton/util/beans test/java/org/nuiton/util/beans
Author: bleny Date: 2011-09-01 11:53:58 +0200 (Thu, 01 Sep 2011) New Revision: 2198 Url: http://nuiton.org/repositories/revision/nuiton-utils/2198 Log: #1728: fisrt try by computing a diff given two bean. test included Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/Binder.java trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BinderTest.java Modified: trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/Binder.java =================================================================== --- trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/Binder.java 2011-08-30 10:48:22 UTC (rev 2197) +++ trunk/nuiton-utils/src/main/java/org/nuiton/util/beans/Binder.java 2011-09-01 09:53:58 UTC (rev 2198) @@ -25,6 +25,7 @@ package org.nuiton.util.beans; +import org.apache.commons.lang.ObjectUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.util.ObjectUtil; @@ -38,6 +39,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -308,6 +310,177 @@ } } + protected Object readSourceProperty(String sourceProperty, I source) { + try { + Object read = null; + Method readMethod = model.getSourceReadMethod(sourceProperty); + if (source != null) { + // obtain value from source + read = readMethod.invoke(source); + } + // obtain acceptable null value (for primitive types, use + // default values). + if (read == null) { + read = ObjectUtil.getNullValue(readMethod.getReturnType()); + } + if (log.isDebugEnabled()) { + log.debug("property " + sourceProperty + ", type : " + + readMethod.getReturnType() + ", value = " + read); + } + + if (model.containsBinderProperty(sourceProperty)) { + if (model.containsCollectionProperty(sourceProperty)) { + read = bindCollection(sourceProperty, read); + } else { + read = bindProperty(sourceProperty, read); + } + } else if (model.containsCollectionProperty(sourceProperty)) { + + // specific collection strategy is set, must use it + read = getCollectionValue(sourceProperty, read); + } + + return read; + } catch (Exception e) { + throw new RuntimeException( + "could not read property " + sourceProperty + + " on source " + source); + } + } + + protected Object readTargetProperty(String targetProperty, O target) { + try { + Object read = null; + Method readMethod = model.getTargetReadMethod(targetProperty); + if (target != null) { + // obtain value from source + read = readMethod.invoke(target); + } + // obtain acceptable null value (for primitive types, use + // default values). + if (read == null) { + read = ObjectUtil.getNullValue(readMethod.getReturnType()); + } + if (log.isDebugEnabled()) { + log.debug("property " + targetProperty + ", type : " + + readMethod.getReturnType() + ", value = " + read); + } + + if (model.containsBinderProperty(targetProperty)) { + if (model.containsCollectionProperty(targetProperty)) { + read = bindCollection(targetProperty, read); + } else { + read = bindProperty(targetProperty, read); + } + } else if (model.containsCollectionProperty(targetProperty)) { + + // specific collection strategy is set, must use it + read = getCollectionValue(targetProperty, read); + } + + return read; + } catch (Exception e) { + throw new RuntimeException( + "could not read property " + targetProperty + + " on target " + target); + } + } + + public class PropertyDiff { + + protected String sourceProperty; + + protected Object sourceValue; + + protected String targetProperty; + + protected Object targetValue; + + public PropertyDiff() {} + + public PropertyDiff(String sourceProperty, Object sourceValue, String targetProperty, Object targetValue) { + this.sourceProperty = sourceProperty; + this.sourceValue = sourceValue; + this.targetProperty = targetProperty; + this.targetValue = targetValue; + } + + public String getSourceProperty() { + return sourceProperty; + } + + public void setSourceProperty(String sourceProperty) { + this.sourceProperty = sourceProperty; + } + + public Object getSourceValue() { + return sourceValue; + } + + public void setSourceValue(Object sourceValue) { + this.sourceValue = sourceValue; + } + + public String getTargetProperty() { + return targetProperty; + } + + public void setTargetProperty(String targetProperty) { + this.targetProperty = targetProperty; + } + + public Object getTargetValue() { + return targetValue; + } + + public void setTargetValue(Object targetValue) { + this.targetValue = targetValue; + } + } + + protected List<PropertyDiff> diff(I source, O target, boolean excludeProperties, + String... propertyNames) { + if (target == null) { + throw new NullPointerException("parameter 'target' can no be null"); + } + + propertyNames = excludeProperties ? + getAllPropertiesExclude(propertyNames) : + getProperties(propertyNames); + + List<PropertyDiff> result = new LinkedList<PropertyDiff>(); + + for (String sourceProperty : propertyNames) { + + Object sourceRead = readSourceProperty(sourceProperty, source); + + String targetProperty = model.getTargetProperty(sourceProperty); + + Object targetRead = readTargetProperty(targetProperty, target); + + if (ObjectUtils.notEqual(sourceRead, targetRead)) { + PropertyDiff propertyDiff = new PropertyDiff(sourceProperty, sourceRead, targetProperty, targetRead); + result.add(propertyDiff); + } + } + + return result; + } + + /** Compare two beans property by property according to the model. + * + * List contains one element per property with different values (according + * to the result of an equals() call) + * + * @param source a bean of type I + * @param target a bean of type O + * @return a list with all the properties which values differ in source + * and target. Properties with equal values are not included. + */ + public List<PropertyDiff> diff(I source, O target) { + return diff(source, target, false); + } + /** * Get the model of the binder. * Modified: trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BinderTest.java =================================================================== --- trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BinderTest.java 2011-08-30 10:48:22 UTC (rev 2197) +++ trunk/nuiton-utils/src/test/java/org/nuiton/util/beans/BinderTest.java 2011-09-01 09:53:58 UTC (rev 2198) @@ -31,6 +31,7 @@ import org.junit.BeforeClass; import org.junit.Test; +import java.util.List; import java.util.Map; public class BinderTest { @@ -101,7 +102,7 @@ } @Test - public void testObtainProperties() throws Exception { + public void testObtainProperties() { Map<String, Object> map; map = binderA.obtainProperties(a); Assert.assertEquals(0, map.size()); @@ -142,7 +143,7 @@ } @Test - public void testCopy() throws Exception { + public void testCopy() { a.setA(VALUE_A); a.setB(VALUE_B); @@ -172,7 +173,7 @@ } @Test - public void testCopyIncluding() throws Exception { + public void testCopyIncluding() { a.setA(VALUE_A); a.setB(VALUE_B); @@ -189,7 +190,7 @@ } @Test - public void testCopyExcluding() throws Exception { + public void testCopyExcluding() { a.setA(VALUE_A); a.setB(VALUE_B); @@ -224,4 +225,26 @@ Assert.assertEquals(VALUE_E, b.getE2()); } + + @Test + public void testDiff() { + a.setA(VALUE_A); + b.setA(VALUE_A); + a.setB(VALUE_A); + b.setB(VALUE_B); + + List<Binder<BeanA, BeanB>.PropertyDiff> diff = binderB.diff(a, b); + + // only one property has changed + Assert.assertEquals(1, diff.size()); + + // names of the properties used for comparison + Binder.PropertyDiff propertyDiff = diff.get(0); + Assert.assertEquals(BeanA.PROPERTY_B, propertyDiff.getSourceProperty()); + Assert.assertEquals(BeanB.PROPERTY_B, propertyDiff.getTargetValue()); + + // old and new values + Assert.assertEquals(VALUE_A, propertyDiff.getSourceValue()); + Assert.assertEquals(VALUE_B, propertyDiff.getTargetValue()); + } }
participants (1)
-
bleny@users.nuiton.org