2012-01-17 15 views
18

C'è una biblioteca che può fare il seguente ?:Impostare campi oggetto da HashMap

Dato un oggetto e un HashMap, enumera le chiavi della HashMap e cerca il setter per queste chiavi nell'oggetto e imposta i valori associati. Qualcosa di simile alla ricerca:

public Object setData(Object object, HashMap<String, Object> fields) { 
    for (Entry<String, Object> entry : fields.entrySet()) { 
     Method m = object.getClass().getMethod("set" + entry.getKey(), entry.getValue().getClass()); 
     if (m != null) { 
     m.invoke(object, entry.getValue()); 
     } 
    } 
    return object; 
} 

Il compito sembra semplice al primo sguardo, ma ci sono alcune sfumature che spero che qualcuno ha già preso cura di. Come sapete, reinventare la ruota (la buona ruota) è un approccio sbagliato.

risposta

17

Look at Apache Commons BeanUtils

org.apache.commons.beanutils.BeanUtils.populate(Object bean, Map properties) 

Javadoc:
popolano le proprietà JavaBeans del fagiolo specificato, sulla base delle coppie nome/valore specificato. Questo metodo utilizza API di riflessione Java per identificare i corrispondenti nomi di metodo "proprietà setter" e gestisce gli argomenti setter di tipo String, booleano, int, long, float e double.

+2

L'avvertenza "si occupa solo degli argomenti setter di tipo String, booleano, int, long, flat e double" è MOLTO degno di nota, per questo motivo credo che la risposta sottostante (ma usando BeanUtils.copyProperty() piuttosto che BeanUtils.setProperty()) è l'alternativa migliore. – fragorl

6

Migliore utilizzo BeanUtils classe:

public Object setData(Object object, HashMap<String, Object> fields) { 
    for(Entry<String, Object> entry : fields.entrySet()) { 
     BeanUtils.setProperty(object, entry.getKey(), entry.getValue()); 
    } 
    return object; 
} 
+0

Grazie @Wojtek O., con il tuo suggerimento ho trovato il metodo di popolamento giusto prima che l'e-zinco rispondesse con esso! – forker

3

Ho una classe BeanAsMap che ho scritto molto tempo fa. Il metodo asMap restituisce un Map che è una vista su un bean Java (POJO). È possibile chiamare putAll su quello Map, passandogli il numero Map da cui si desidera copiare i dati.

Sentitevi liberi di usare il mio codice sopra menzionato.

Esempio:

MyClass bean = ...; 
Map<String, Object> inputData = ...; 

Map<String, Object> view = BeanAsMap.asMap(bean); 
view.putAll(inputData); 
+0

Il tuo codice va bene @Jesper, ma la domanda è 'Mappa -> Bean' e ** NOT **' Bean -> Mappa' –

+1

@FelipeConde Il mio codice funziona in due modi: puoi creare una nuova istanza di una classe bean, quindi avvolgilo con 'BeanAsMap' e chiama' put' sulla mappa che imposterà le proprietà del bean.Se hai una mappa esistente, puoi chiamare 'putAll' sulla mappa wrapper per copiare i valori della mappa esistente nel bean. – Jesper

2

BeanUtils va bene.

Ma, come buona pratica, non scriverei codice che utilizza la riflessione. O come l'ultima soluzione che ho, se nessun altro è stato trovato.

Questo codice non può essere rintracciato in IDE come Eclipse (nessuna gerarchia di chiamata), facendo credere allo sviluppatore che i setter non vengano mai chiamati. Può rompere il tuo codice e questo verrà comunque compilato.

Troppo alto livello di astrazione come questo rende il codice difficile da capire.

Il codice che viene offuscato verrà interrotto dall'offfuscator stesso durante la scrittura di tali elementi.

La soluzione migliore sarebbe ripensare l'uso della riflessione per impostare i campi dell'oggetto.

+0

Non potrei essere più d'accordo. –

+1

Anche se sono d'accordo sul fatto che la riflessione non debba essere usata come uno strumento generico, ci sono occasionalmente buoni motivi per usarla (ad esempio, impostando le proprietà di un oggetto Bean da JSON o altra fonte dinamica). –