diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java index 14e79764b..84ecb7951 100644 --- a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java +++ b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java @@ -88,12 +88,12 @@ 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); } @@ -120,6 +120,34 @@ public static void copyProperty(final Object bean, final String name, final Obje } + /** + *
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);
+ }
+
+
/**
* Create a cache.
* @param the key type of the cache
diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java
index ca9ff0370..9e58ca757 100644
--- a/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java
+++ b/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java
@@ -22,6 +22,7 @@
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
@@ -288,7 +289,56 @@ private Object convertForCopy(final Object value, final Class> type) {
* 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) {
throw new IllegalArgumentException
@@ -311,7 +361,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);
}
@@ -323,7 +373,7 @@ public void copyProperties(final Object dest, final Object orig)
Map propMap = (Map) orig;
for (final Map.Entry entry : propMap.entrySet()) {
final String k = entry.getKey();
- if (getPropertyUtils().isWriteable(dest, k)) {
+ if (getPropertyUtils().isWriteable(dest, k) && !Arrays.asList(ignore).contains(k)) {
copyProperty(dest, k, entry.getValue());
}
}
@@ -336,7 +386,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/BeanUtilsBeanTestCase.java b/src/test/java/org/apache/commons/beanutils2/BeanUtilsBeanTestCase.java
index e4a29a907..04f56ee95 100644
--- a/src/test/java/org/apache/commons/beanutils2/BeanUtilsBeanTestCase.java
+++ b/src/test/java/org/apache/commons/beanutils2/BeanUtilsBeanTestCase.java
@@ -377,6 +377,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 narrowing and widening conversions on byte.
*/
diff --git a/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java b/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java
index 6cf346fb8..3e907baef 100644
--- a/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java
+++ b/src/test/java/org/apache/commons/beanutils2/BeanUtilsBenchCase.java
@@ -163,6 +163,17 @@ public void testCopyPropertiesBean() throws Exception {
stopMillis = System.currentTimeMillis();
System.err.println("BU.copyProperties(dyna,bean), count=" + counter + ", time=" + (stopMillis - startMillis));
+ final String[] ignore = new String[] { "booleanProperty", "floatProperty", null, ""};
+
+ startMillis = System.currentTimeMillis();
+ for (long i = 0; i < counter; i++) {
+ bu.copyProperties(outDyna, inBean, ignore);
+ }
+ stopMillis = System.currentTimeMillis();
+
+ System.err.println("BU.copyProperties(dyna,bean, ignore), count=" + counter +
+ ", time=" + (stopMillis - startMillis));
+
}
// Time copyProperties() from a DynaBean