diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtils.java b/src/main/java/org/apache/commons/beanutils2/BeanUtils.java index 14e79764b..828255cba 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); } diff --git a/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java b/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java index ca9ff0370..bcf99deba 100644 --- a/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java +++ b/src/main/java/org/apache/commons/beanutils2/BeanUtilsBean.java @@ -288,7 +288,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 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
+ * @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 +360,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 +372,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 +385,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..ffd1e90be 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..4f16e9bbd 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, ""};
+
+ 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