2009-05-07 15 views
14

Ho un semplice POJO Java che vorrei copiare le proprietà su un'altra istanza della stessa classe POJO.Come copiare le proprietà da un bean Java a un altro?

So che posso farlo con BeanUtils.copyProperties() ma vorrei evitare l'uso di una libreria di terze parti.

Quindi, come fare in modo semplice, il modo corretto e più sicuro?

A proposito, sto usando Java 6.

+8

Um, BeanUtils.copyProperties() * è * il modo corretto. È in quella libreria perché non esiste un modo semplice per farlo diversamente. Se davvero non si desidera utilizzare BeanUtils, quindi scaricare il codice sorgente per esso e copiare il metodo. – skaffman

+1

skaffman - Non ho visto il tuo commento quando ho postato la mia risposta, mi dispiace. Ma come puoi vedere sono completamente d'accordo con te :) – MetroidFan2002

+1

Nota che Spring include anche un [BeanUtils.copyProperties] (http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/beans /BeanUtils.html) metodo che potrebbe essere più conveniente se stai già utilizzando Spring. – pimlottc

risposta

12

Credo che se si guarda il codice sorgente di BeanUtils, che vi mostrerà come fare questo senza utilizzare BeanUtils.

Se si desidera semplicemente creare una copia di un POJO (non proprio la stessa cosa di copiare le proprietà da un POJO a un altro), è possibile modificare il bean di origine per implementare il metodo clone() e l'interfaccia Cloneable.

+1

Se tutte le proprietà sono supportate da campi, è opportuno che la clonazione funzioni correttamente e sia molto efficiente. Tuttavia, si noti che si tratta di una copia poco profonda ... –

+1

È una copia superficiale se si implementa semplicemente Cloneable e overrid clone() per renderlo pubblico e chiamare l'implementazione genitore. Ma ovviamente, potresti implementare clone() per fare qualsiasi cosa, inclusa la creazione di una copia profonda. Controlla 'Efficace Java' per ulteriori dettagli su clone(). –

2

Dai un'occhiata allo JavaBeans API, in particolare alla classe Introspector. È possibile utilizzare i metadati BeanInfo nelle proprietà get e set. È una buona idea leggere il JavaBeans specification se non l'hai già fatto. Aiuta anche ad avere familiarità con lo reflection API.

+0

Un buon consiglio, ma probabilmente è giusto assumere il risultato finale di tutto ciò che probabilmente sarà un'implementazione inferiore di BeanUtils.copyProperties() –

+0

Questo è un commento corretto, ma non fa mai male sapere cosa sta succedendo. – McDowell

+0

Thx. Sono nuovo con Java 6, quindi speravo che ci fosse un modo per farlo più facilmente rispetto alle versioni precedenti. Ma darò sicuramente un'occhiata ai tuoi link. – paulgreg

1

è nessun modo semplice per farlo. Introspector e le librerie di bean Java sono monolitiche - BeanUtils è un semplice wrapper e funziona bene. Non avere le librerie solo per non avere librerie è una cattiva idea in generale - c'è un motivo per cui è comune cominciare - funzionalità comuni che dovrebbero esistere con Java, ma non lo fa.

10

Ho avuto lo stesso problema durante lo sviluppo di un'app per Google App Engine, in cui non potevo utilizzare BeanUtils a causa delle restrizioni di registrazione. Ad ogni modo, ho trovato questa soluzione e ha funzionato bene per me.

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(); 
    } 
} 

Qualsiasi miglioramento o raccomandazione sono davvero benvenuti.

+1

Grazie, mi hai aiutato con questa domanda: http://stackoverflow.com/questions/8384814/when-can-propertyutils-copyproperties-fail-silently Ti suggerisco di aggiungere il supporto per le proprietà di sola lettura controllando se 'propertyDescriptor.getWriteMethod() 'restituisce null. – ripper234

+1

Grazie per la raccomandazione. Ho modificato la mia risposta per aggiungere il supporto per le proprietà di sola lettura. – Efthymis

1

Mi sono imbattuto in alcuni problemi con Introspector.getBeanInfo non restituendo tutte le proprietà, quindi ho finito per implementare una copia campo anziché la copia della proprietà.

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

Un'altra alternativa è MapStruct che genera codice di mappatura in fase di compilazione, con conseguente mapping dei tipi di sicurezza che non richiedono alcuna dipendenza in fase di esecuzione (Disclaimer: io sono l'autore di MapStruct).

3

Ehi amici basta usare la mia classe ReflectionUtil creata per copiare i valori di un bean in un altro bean simile. Questa classe inoltre copierà l'oggetto Collections.

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

Nota: Questo bean deve avere simile nome variabili con il tipo e hanno getter e setter per loro.

Ora vengono aggiunte ulteriori funzionalità. Puoi anche copiare i dati di un'entità nel suo bean. Se un'entità ha un'altra entità in essa, è possibile passare l'opzione mappa per la modifica di runtime dell'entità interna al relativo bean.

Es.

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); 

Questo caso è molto utile quando i vostri Entità contiene relazione.

0

È possibile raggiungerlo utilizzando 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); 
    } 
} 
Problemi correlati