Hi all!
I'm Rodrigo di Lorenzo Lopes and I'd like to do some contributions to
commons apache project (despite my poor English Knowledge).
So, I have one problem with BeanUtils.copyProperties: From a source, I
have a bean partialy populated. From another source, I have the same
bean with others informations. How can I merge these beans?
My solutions is: verify an mustOverwrite method before each
copyProperty call. See the patch in attachment.
;)
Best Regards,
Rodrigo
------------------------------------------------------------------------
Index:
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java
===================================================================
---
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java
(revision 617468)
+++
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/test/org/apache/commons/beanutils/BeanUtilsTestCase.java
(working copy)
@@ -20,6 +20,7 @@
import java.lang.reflect.InvocationTargetException;
import java.util.Calendar;
+import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
@@ -1637,4 +1638,28 @@
}
return false;
}
+
+ public void testMergeProperty() throws Exception {
+ TestBean testBean = new TestBean();
+ testBean.setStringProperty("string");
+ HashMap hashmapTest = new HashMap();
+ testBean.setMapProperty(null);
+ Date date = new Date();
+ testBean.setDateProperty(date);
+ TestBean testBean2 = new TestBean();
+ testBean2.setStringProperty("string2");
+ testBean2.setMapProperty(hashmapTest);
+ testBean2.setDateProperty(null);
+ BeanUtilsBean.getInstance().mergeProperties(testBean, testBean2, new
Overwritable() {
+
+ public boolean mustOverwrite(String propertyName,
Object originValue) {
+ if (originValue != null) return true;
+ return false;
+ }
+
+ });
+ assertEquals(testBean.getStringProperty(), "string2");
+ assertEquals(testBean.getMapProperty(), hashmapTest);
+ assertEquals(testBean.getDateProperty(), date);
+ }
}
Index:
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/java/org/apache/commons/beanutils/Overwritable.java
===================================================================
---
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/java/org/apache/commons/beanutils/Overwritable.java
(revision 0)
+++
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/java/org/apache/commons/beanutils/Overwritable.java
(revision 0)
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.beanutils;
+/**
+ * <p>Interface to know when a property must be overwrite.</p>
+ * <p>See mergeProperties [EMAIL PROTECTED] BeanUtils}.</p>
+ * @author Rodrigo di Lorenzo Lopes
+ * @version 1.0
+ * @since 3.3
+ *
+ */
+public interface Overwritable {
+
+ /**
+ * Determine if property must be overwrite.
+ * @param propertyName Property name
+ * @param value Value from origin bean
+ * @return true, if method must be overwrite.
+ */
+ public boolean mustOverwrite(String propertyName, Object originValue);
+
+}
Index:
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/java/org/apache/commons/beanutils/BeanUtilsBean.java
===================================================================
---
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/java/org/apache/commons/beanutils/BeanUtilsBean.java
(revision 617468)
+++
C:/desenvolvimento/workspace_3.3/Commons-BeanUtils/src/java/org/apache/commons/beanutils/BeanUtilsBean.java
(working copy)
@@ -190,8 +190,9 @@
/**
- * <p>Copy property values from the origin bean to the destination bean
- * for all cases where the property names are the same. For each
+ * <p>Merge property values from the origin bean to the destination bean
+ * for all cases where the property names are the same, and always where
+ * method mustOverwrite of overwritable return true. For each
* property, a conversion is attempted as necessary. All combinations of
* standard JavaBeans and DynaBeans as origin and destination are
* supported. Properties that exist in the origin bean, but do not exist
@@ -205,22 +206,17 @@
* is intended to perform a "shallow copy" of the properties and so complex
* properties (for example, nested ones) will not be copied.</p>
*
- * <p>This method differs from <code>populate()</code>, which
- * was primarily designed for populating JavaBeans from the map of request
- * parameters retrieved on an HTTP request, is that no scalar->indexed
- * or indexed->scalar manipulations are performed. If the origin property
- * is indexed, the destination property must be also.</p>
+ * <p>This method differs from <code>copyProperties()</code>, which
+ * always overwrite destination bean with origin bean values. </p>
*
- * <p>If you know that no type conversions are required, the
- * <code>copyProperties()</code> method in [EMAIL PROTECTED]
PropertyUtils} will
- * execute faster than this method.</p>
- *
* <p><strong>FIXME</strong> - Indexed and mapped properties that do not
* have getter and setter methods for the underlying array or Map are not
* copied by this method.</p>
*
* @param dest Destination bean whose properties are modified
* @param orig Origin bean whose properties are retrieved
+ * @param overwritable Overwritable whose determines when origin bean
value must overwrite
+ * destination bean
*
* @exception IllegalAccessException if the caller does not have
* access to the property accessor method
@@ -231,7 +227,7 @@
* @exception InvocationTargetException if the property accessor method
* throws an exception
*/
- public void copyProperties(Object dest, Object orig)
+ public void mergeProperties(Object dest, Object orig, Overwritable
overwritable)
throws IllegalAccessException, InvocationTargetException {
// Validate existence of the specified beans
@@ -258,6 +254,7 @@
if (getPropertyUtils().isReadable(orig, name) &&
getPropertyUtils().isWriteable(dest, name)) {
Object value = ((DynaBean) orig).get(name);
+ if (overwritable.mustOverwrite(name, value))
copyProperty(dest, name, value);
}
}
@@ -267,6 +264,7 @@
String name = (String) names.next();
if (getPropertyUtils().isWriteable(dest, name)) {
Object value = ((Map) orig).get(name);
+ if (overwritable.mustOverwrite(name, value))
copyProperty(dest, name, value);
}
}
@@ -283,9 +281,10 @@
try {
Object value =
getPropertyUtils().getSimpleProperty(orig, name);
+ if (overwritable.mustOverwrite(name, value))
copyProperty(dest, name, value);
} catch (NoSuchMethodException e) {
- // Should not happen
+ ; // Should not happen
}
}
}
@@ -293,7 +292,56 @@
}
+ /**
+ * <p>Copy property values from the origin bean to the destination bean
+ * for all cases where the property names are the same. For each
+ * property, a conversion is attempted as necessary. All combinations of
+ * standard JavaBeans and DynaBeans as origin and destination are
+ * supported. Properties that exist in the origin bean, but do not exist
+ * in the destination bean (or are read-only in the destination bean) are
+ * silently ignored.</p>
+ *
+ * <p>If the origin "bean" is actually a <code>Map</code>, it is assumed
+ * to contain String-valued <strong>simple</strong> property names as the
keys, pointing at
+ * the corresponding property values that will be converted (if necessary)
+ * and set in the destination bean. <strong>Note</strong> that this method
+ * is intended to perform a "shallow copy" of the properties and so complex
+ * properties (for example, nested ones) will not be copied.</p>
+ *
+ * <p>This method differs from <code>populate()</code>, which
+ * was primarily designed for populating JavaBeans from the map of request
+ * parameters retrieved on an HTTP request, is that no scalar->indexed
+ * or indexed->scalar manipulations are performed. If the origin property
+ * is indexed, the destination property must be also.</p>
+ *
+ * <p>If you know that no type conversions are required, the
+ * <code>copyProperties()</code> method in [EMAIL PROTECTED]
PropertyUtils} will
+ * execute faster than this method.</p>
+ *
+ * <p><strong>FIXME</strong> - Indexed and mapped properties that do not
+ * have getter and setter methods for the underlying array or Map are not
+ * copied by this method.</p>
+ *
+ * @param dest Destination bean whose properties are modified
+ * @param orig Origin bean whose properties are retrieved
+ *
+ * @exception IllegalAccessException if the caller does not have
+ * access to the property accessor method
+ * @exception IllegalArgumentException if the <code>dest</code> or
+ * <code>orig</code> argument is null
+ * @exception InvocationTargetException if the property accessor method
+ * throws an exception
+ */
+ public void copyProperties(Object dest, Object orig)
+ throws IllegalAccessException, InvocationTargetException {
+ mergeProperties(dest, orig, new Overwritable() {
+ public boolean mustOverwrite(String property, Object
value) {
+ return true;
+ }});
+ }
+
+
/**
* <p>Copy the specified property value to the specified destination bean,
* performing any type conversion that is required. If the specified