diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java index eae086d7f..292c38eb6 100644 --- a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java +++ b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java @@ -89,12 +89,39 @@ public static Object cloneBean(final Object bean) * converter has not been registered. * @throws InvocationTargetException if the property accessor method * throws an exception - * @see BeanUtilsBean#copyProperties + * @see BeanUtilsBean#copyProperties(Object, Object, String...) */ public static void copyProperties(final Object dest, final Object orig) throws IllegalAccessException, InvocationTargetException { - BeanUtilsBean.getInstance().copyProperties(dest, orig); + copyProperties(dest, orig, (String) null); + } + + /** + *
Copy property values from the origin bean to the destination bean + * for all cases where the property names are the same
+ * + *For more details see {@code BeanUtilsBean}.
+ * + * @param dest Destination bean whose properties are modified + * @param orig Origin bean whose properties are retrieved + * @param ignore list of properties to ignore, may be null + * + * @throws IllegalAccessException if the caller does not have + * access to the property accessor method + * @throws IllegalArgumentException if the {@code dest} or + * {@code orig argument is null or if thedest}
+ * property type is different from the source type and the relevant
+ * converter has not been registered.
+ * @throws InvocationTargetException if the property accessor method
+ * throws an exception
+ * @see BeanUtilsBean#copyProperties(Object, Object, String...)
+ * @since 2.0
+ */
+ public static void copyProperties(final Object dest, final Object orig, final String... ignore)
+ throws IllegalAccessException, InvocationTargetException {
+
+ BeanUtilsBean.getInstance().copyProperties(dest, orig, ignore);
}
diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java
index 1d3832a58..cf7e5df8b 100644
--- a/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java
+++ b/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java
@@ -23,6 +23,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -222,7 +223,56 @@ public Object cloneBean(final Object bean)
* throws an exception
*/
public void copyProperties(final Object dest, final Object orig)
- throws IllegalAccessException, InvocationTargetException {
+ throws IllegalAccessException, InvocationTargetException {
+ copyProperties(dest, orig, (String) null);
+ }
+
+ /**
+ * 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.
+ *
+ * If the origin "bean" is actually a {@code Map}, it is assumed
+ * to contain String-valued simple property names as the keys, pointing at
+ * the corresponding property values that will be converted (if necessary)
+ * and set in the destination bean. Note 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.
+ *
+ * This method differs from {@code populate()}, 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.
+ *
+ * If you know that no type conversions are required, the
+ * {@code copyProperties()} method in {@link PropertyUtils} will
+ * execute faster than this method.
+ *
+ * FIXME - Indexed and mapped properties that do not
+ * have getter and setter methods for the underlying array or Map are not
+ * copied by this method.
+ *
+ * @param dest Destination bean whose properties are modified
+ * @param orig Origin bean whose properties are retrieved
+ * @param ignore list of properties to ignore, may be null
+ *
+ * @throws IllegalAccessException if the caller does not have
+ * access to the property accessor method
+ * @throws IllegalArgumentException if the {@code dest} or
+ * {@code orig argument is null or if the dest}
+ * property type is different from the source type and the relevant
+ * converter has not been registered.
+ * @throws InvocationTargetException if the property accessor method
+ * throws an exception
+ * @since 2.0
+ */
+ public void copyProperties(final Object dest, final Object orig, final String... ignore)
+ throws IllegalAccessException, InvocationTargetException {
// Validate existence of the specified beans
if (dest == null) {
@@ -246,7 +296,7 @@ public void copyProperties(final Object dest, final Object orig)
// Need to check isReadable() for WrapDynaBean
// (see Jira issue# BEANUTILS-61)
if (getPropertyUtils().isReadable(orig, name) &&
- getPropertyUtils().isWriteable(dest, name)) {
+ getPropertyUtils().isWriteable(dest, name) && !Arrays.asList(ignore).contains(name)) {
final Object value = ((DynaBean) orig).get(name);
copyProperty(dest, name, value);
}
@@ -258,7 +308,7 @@ public void copyProperties(final Object dest, final Object orig)
Map propMap = (Map) orig;
for (final Map.Entry entry : propMap.entrySet()) {
final String name = entry.getKey();
- if (getPropertyUtils().isWriteable(dest, name)) {
+ if (getPropertyUtils().isWriteable(dest, name) && !Arrays.asList(ignore).contains(name)) {
copyProperty(dest, name, entry.getValue());
}
}
@@ -271,7 +321,7 @@ public void copyProperties(final Object dest, final Object orig)
continue; // No point in trying to set an object's class
}
if (getPropertyUtils().isReadable(orig, name) &&
- getPropertyUtils().isWriteable(dest, name)) {
+ getPropertyUtils().isWriteable(dest, name) && !Arrays.asList(ignore).contains(name)) {
try {
final Object value =
getPropertyUtils().getSimpleProperty(orig, name);
diff --git a/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java b/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java
index ff9eae9bf..cda096620 100644
--- a/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java
+++ b/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java
@@ -189,6 +189,17 @@ public void testCopyPropertiesBean() throws Exception {
System.err.println("BU.copyProperties(dyna,bean), count=" + counter +
", time=" + (stop - start));
+ final String[] ignore = new String[] { "booleanProperty", "floatProperty", null, ""};
+
+ start = System.currentTimeMillis();
+ for (long i = 0; i < counter; i++) {
+ bu.copyProperties(outDyna, inBean, ignore);
+ }
+ stop = System.currentTimeMillis();
+
+ System.err.println("BU.copyProperties(dyna,bean, ignore), count=" + counter +
+ ", time=" + (stop - start));
+
}
// Time copyProperties() from a DynaBean
diff --git a/src/test/java/org/apache/commons/beanutils2/BeanUtilsTestCase.java b/src/test/java/org/apache/commons/beanutils2/BeanUtilsTestCase.java
index 69347fc26..eed045985 100644
--- a/src/test/java/org/apache/commons/beanutils2/BeanUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/beanutils2/BeanUtilsTestCase.java
@@ -369,6 +369,43 @@ public void testCopyPropertiesStandard() {
}
+ /**
+ * Test the copyProperties() method from a standard JavaBean.
+ */
+ public void testCopyPropertiesStandardIgnore() {
+ // Set up an origin bean with customized properties
+ final TestBean orig = new TestBean();
+ orig.setBooleanProperty(false);
+ orig.setStringProperty("Ignore Property");
+
+
+ // Copy the origin bean to our destination test bean
+ try {
+ BeanUtils.copyProperties(bean, orig, "stringProperty");
+ } catch (final Exception e) {
+ fail("Threw exception: " + e);
+ }
+ assertEquals("Not Copied array property",
+ "This is a string",
+ bean.getStringProperty());
+
+ final Map map = new HashMap<>();
+ map.put("booleanProperty", "false");
+ map.put("byteProperty", "111");
+ map.put("stringProperty", "Ignore Property");
+
+ try {
+ BeanUtils.copyProperties(bean, map,"stringProperty");
+ } catch (final Throwable t) {
+ fail("Threw " + t.toString());
+ }
+
+ assertEquals("Not Copied array property",
+ "This is a string",
+ bean.getStringProperty());
+
+ }
+
/**
* Test the describe() method.
*/