views:

1666

answers:

2

Hi everyone,

I'm using BeanUtils.copyProperties to copy the entire content of one object into another that inherit from it.

Here is the context, the domain object from which the values are copied contains a Set of objects of custom type Xref. That custom type has an embedded class with various fields of various class types.

For some reason one of the field from an object encapsulated within the embedded object does not get copied over. But most everything else I need do get copied over.

With an example:

class Source {
private Set<Xref> xref;
...
}

class Xref {
...
public static class primaryKey {
...
private MyObj obj;
}
}

class MyObj {
private Integer id;
...
}

Using those names if I try to use BeanUtils.copyProperties to copy the content of a "Source" object into a "SourceExtended" object the value of source.xrefs.get(0).getPrimaryKey().getObj().getId() does not get copied over. In the original object it has a value but in the target object it's null...

Any idea why???

Thank you.

+3  A: 

From the Javadocs:

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.

Phill Sacre
Got it! I'll work around that then. Thank you.
Lancelot
+1  A: 

Here's how I handle this with Spring. Might be of some help. My method is a copy of Spring's shallowCopyFieldState but allows the use of a field filter. Ignores statics and finals.

My method

public static void shallowCopyFieldState(final Object src, final Object dest, final FieldFilter filter)
  throws IllegalArgumentException {
 if (src == null) {
  throw new IllegalArgumentException("Source for field copy cannot be null");
 }
 if (dest == null) {
  throw new IllegalArgumentException("Destination for field copy cannot be null");
 }
 if (!src.getClass().isAssignableFrom(dest.getClass())) {
  throw new IllegalArgumentException("Destination class [" + dest.getClass().getName()
    + "] must be same or subclass as source class [" + src.getClass().getName() + "]");
 }
 org.springframework.util.ReflectionUtils.doWithFields(src.getClass(),
   new org.springframework.util.ReflectionUtils.FieldCallback() {
    public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
     org.springframework.util.ReflectionUtils.makeAccessible(field);
     final Object srcValue = field.get(src);
     field.set(dest, srcValue);
    }
   }, filter);
}

Spring's doWithFields:

/**
 * Invoke the given callback on all fields in the target class,
 * going up the class hierarchy to get all declared fields.
 * @param targetClass the target class to analyze
 * @param fc the callback to invoke for each field
 * @param ff the filter that determines the fields to apply the callback to
 */
public static void doWithFields(Class targetClass, FieldCallback fc, FieldFilter ff)
  throws IllegalArgumentException {

 // Keep backing up the inheritance hierarchy.
 do {
  // Copy each field declared on this class unless it's static or file.
  Field[] fields = targetClass.getDeclaredFields();
  for (int i = 0; i < fields.length; i++) {
   // Skip static and final fields.
   if (ff != null && !ff.matches(fields[i])) {
    continue;
   }
   try {
    fc.doWith(fields[i]);
   }
   catch (IllegalAccessException ex) {
    throw new IllegalStateException(
      "Shouldn't be illegal to access field '" + fields[i].getName() + "': " + ex);
   }
  }
  targetClass = targetClass.getSuperclass();
 }
 while (targetClass != null && targetClass != Object.class);
}
HonkHonkHonk