2009-05-07 33 views
14

Tengo un POJO Java simple que me gustaría copiar las propiedades a otra instancia de la misma clase POJO.¿Cómo copiar propiedades de un bean Java a otro?

Sé que puedo hacer eso con BeanUtils.copyProperties() pero me gustaría evitar el uso de una biblioteca de terceros.

Entonces, ¿cómo hacer eso de forma sencilla y segura?

Por cierto, estoy usando Java 6.

+8

Um, BeanUtils.copyProperties() * es * la forma correcta. Está en esa biblioteca porque no hay una manera fácil de hacerlo de otra manera. Si realmente no desea utilizar BeanUtils, descargue el código fuente y copie el método. – skaffman

+1

skaffman - No vi tu comentario cuando publiqué mi respuesta, lo siento. Pero como puede ver, estoy completamente de acuerdo con usted :) – MetroidFan2002

+1

Tenga en cuenta que Spring también incluye un [BeanUtils.copyProperties] (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans /BeanUtils.html) método que puede ser más conveniente si ya está utilizando Spring. – pimlottc

Respuesta

12

supongo que si nos fijamos en el código fuente de BeanUtils, se le mostrará cómo hacer esto sin usar BeanUtils.

Si simplemente desea crear una copia de un POJO (no exactamente lo mismo que copiar las propiedades de un POJO a otro), podría cambiar el bean fuente para implementar el método clone() y la interfaz Cloneable.

+1

Si todas las propiedades están respaldadas por campos, hacerlo clonable debería funcionar muy bien y es muy eficiente. Sin embargo, tenga en cuenta que es una copia superficial ... –

+1

Es una copia superficial si simplemente implementa Cloneable y overrid clone() para hacerlo público y llamar a la implementación principal. Pero, por supuesto, podría implementar clone() para hacer cualquier cosa, incluida la creación de una copia profunda. Consulte "Java efectivo" para obtener más información sobre clone(). –

2

Eche un vistazo a JavaBeans API, en particular la clase Introspector. Puede usar los metadatos BeanInfo en get y set propiedades. Es una buena idea leer en el JavaBeans specification si aún no lo ha hecho. También ayuda tener una familiaridad pasajera con el reflection API.

+0

Un buen consejo, pero probablemente sea justo suponer que el resultado final de todo esto probablemente será una implementación inferior de BeanUtils.copyProperties() –

+0

. Es un comentario justo, pero nunca está de más saber lo que está pasando. – McDowell

+0

Thx. Soy nuevo con Java 6, así que espero que haya una forma de hacerlo más fácilmente que en versiones anteriores. Pero definitivamente voy a echar un vistazo a tus enlaces. – paulgreg

1

There es no es una forma sencilla de hacerlo. Introspector y las bibliotecas de beans de Java son monolíticas. BeanUtils es un envoltorio simple que funciona bien. No tener bibliotecas solo para no tener bibliotecas es una mala idea en general, hay una razón por la que es común comenzar, una funcionalidad común que debería existir con Java, pero no es así.

10

Tuve el mismo problema al desarrollar una aplicación para Google App Engine, donde no pude usar BeanUtils debido a las restricciones de registro de commons. De todos modos, se me ocurrió esta solución y funcionó muy bien para mí.

public static void copyProperties(Object fromObj, Object toObj) { 
    Class<? extends Object> fromClass = fromObj.getClass(); 
    Class<? extends Object> toClass = toObj.getClass(); 

    try { 
     BeanInfo fromBean = Introspector.getBeanInfo(fromClass); 
     BeanInfo toBean = Introspector.getBeanInfo(toClass); 

     PropertyDescriptor[] toPd = toBean.getPropertyDescriptors(); 
     List<PropertyDescriptor> fromPd = Arrays.asList(fromBean 
       .getPropertyDescriptors()); 

     for (PropertyDescriptor propertyDescriptor : toPd) { 
      propertyDescriptor.getDisplayName(); 
      PropertyDescriptor pd = fromPd.get(fromPd 
        .indexOf(propertyDescriptor)); 
      if (pd.getDisplayName().equals(
        propertyDescriptor.getDisplayName()) 
        && !pd.getDisplayName().equals("class")) { 
       if(propertyDescriptor.getWriteMethod() != null)     
         propertyDescriptor.getWriteMethod().invoke(toObj, pd.getReadMethod().invoke(fromObj, null)); 
      } 

     } 
    } catch (IntrospectionException e) { 
     e.printStackTrace(); 
    } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
    } catch (IllegalAccessException e) { 
     e.printStackTrace(); 
    } catch (InvocationTargetException e) { 
     e.printStackTrace(); 
    } 
} 

Cualquier mejora o recomendación es realmente bienvenida.

+1

Gracias, me han ayudado con esta pregunta: http://stackoverflow.com/questions/8384814/when-can-propertyutils-copyproperties-fail-silently Le sugiero que agregue compatibilidad con las propiedades de solo lectura al marcar si 'propertyDescriptor.getWriteMethod() 'devuelve nulo. – ripper234

+1

Gracias por la recomendación. Edité mi respuesta para agregar compatibilidad con las propiedades de solo lectura. – Efthymis

1

Tuve algunos problemas con Introspector.getBeanInfo al no devolver todas las propiedades, por lo que terminé implementando una copia de campo en lugar de copiar la propiedad.

public static <T> void copyFields(T target, T source) throws Exception{ 
    Class<?> clazz = source.getClass(); 

    for (Field field : clazz.getFields()) { 
     Object value = field.get(source); 
     field.set(target, value); 
    } 
} 
2

Otra alternativa es MapStruct que genera código de mapeo en tiempo de compilación, lo que resulta en las asignaciones de tipos de fallos que no requieren ninguna dependencia en tiempo de ejecución (Negación: Soy el autor de MapStruct).

3

Hola amigos, simplemente uso mi clase ReflectionUtil creada para copiar los valores de un bean a otro bean similar. Esta clase también copiará el objeto Colecciones.

https://github.com/vijayshegokar/Java/blob/master/Utility/src/common/util/reflection/ReflectionUtil.java

Nota: Este bean debe tener el nombre de variables similares con el tipo y tienen getter y setters para ellos.

Ahora se agregan más funcionalidades. También puede copiar datos de una entidad en su bean. Si una entidad tiene otra entidad, puede pasar la opción de mapa para el cambio en tiempo de ejecución de la entidad interna a su bean relacionado.

Por ejemplo.

ParentEntity parentEntityObject = getParentDataFromDB(); 
Map<Class<?>, Class<?>> map = new HashMap<Class<?>, Class<?>>(); 
map.put(InnerBean1.class, InnerEntity1.class); 
map.put(InnerBean2.class, InnerEntity2.class); 
ParentBean parent = ReflectionUtil.copy(ParentBean.class, parentEntityObject, map); 

Este caso es muy útil cuando sus Entidades tienen relación.

0

Puede lograrlo usando Java Reflection API.

public static <T> void copy(T target, T source) throws Exception { 
    Class<?> clazz = source.getClass(); 

    for (Field field : clazz.getDeclaredFields()) { 
     if (Modifier.isPrivate(field.getModifiers())) 
      field.setAccessible(true); 
     Object value = field.get(source); 
     field.set(target, value); 
    } 
} 
Cuestiones relacionadas