que mapeo example java introspection

mapeo - Introspección de Java: objeto para mapear



mapeo en java (6)

Aquí hay una aproximación aproximada, con suerte suficiente para que apuntes en la dirección correcta:

public Map<String, Object> getMap(Object o) { Map<String, Object> result = new HashMap<String, Object>(); Field[] declaredFields = o.getClass().getDeclaredFields(); for (Field field : declaredFields) { result.put(field.getName(), field.get(o)); } return result; }

Tengo un obj objeto Java que tiene atributos obj.attr1 , obj.attr1 , etc. Posiblemente se acceda a los atributos a través de un nivel extra de indirección: obj.getAttr1() , obj.getAttr2() , si no es público.

El desafío : quiero una función que toma un objeto, y devuelve un Map<String, Object> , donde las claves son cadenas "attr1" , "attr2" etc. y los valores son los objetos correspondientes obj.attr1 , obj.attr2 . Imagino que la función sería invocada con algo así como

  • toMap(obj) ,
  • o toMap(obj, "attr1", "attr3") (donde attr1 y attr3 son un subconjunto de los atributos de obj ),
  • o tal vez a toMap(obj, "getAttr1", "getAttr3") si es necesario.

No sé mucho sobre la introspección de Java: ¿cómo se hace eso en Java?

En este momento, tengo una toMap() especializada toMap() para cada tipo de objeto que me importa, y es demasiado repetitivo.

NOTA : para aquellos que conocen Python, quiero algo como obj.__dict__ . O dict((attr, obj.__getattribute__(attr)) for attr in attr_list) para la variante del subconjunto.


Aquí hay una manera realmente fácil de hacer esto.

Use Jackson JSON lib para convertir el objeto a JSON.

Luego lea el JSON y conviértalo en un Mapa.

El mapa contendrá todo lo que quieras.

Aquí está el 4 del trazador de líneas

ObjectMapper om = new ObjectMapper(); StringWriter sw = new StringWriter(); om.writeValue(object, sw); Map<String, Object> map = om.readValue(sw.toString(), Map.class);

Y la ganancia adicional por supuesto es que esto es recursivo y creará mapas de mapas si es necesario


Ninguno de estos funciona para propiedades anidadas, Object Mapper hace un buen trabajo, excepto que tienes que establecer todos los valores en todos los campos que deseas ver en el mapa e incluso entonces no puedes evitar / ignorar fácilmente las propias anotaciones de @Json en ObjectMapper. de las propiedades. Desafortunadamente, tienes que hacer algo como lo siguiente, es solo un borrador para solo dar una idea.

/* * returns fields that have getter/setters including nested fields as * field0, objA.field1, objA.objB.field2, ... * to take care of recursive duplicates, * simply use a set<Class> to track which classes * have already been traversed */ public static void getBeanUtilsNestedFields(String prefix, Class clazz, List<String> nestedFieldNames) throws Exception { PropertyDescriptor[] descriptors = BeanUtils.getPropertyDescriptors(clazz); for(PropertyDescriptor descr : descriptors){ // if you want values, use: descr.getValue(attributeName) if(descr.getPropertyType().getName().equals("java.lang.Class")){ continue; } // a primitive, a CharSequence(String), Number, Date, URI, URL, Locale, Class, or corresponding array // or add more like UUID or other types if(!BeanUtils.isSimpleProperty(descr.getPropertyType())){ Field collectionfield = clazz.getDeclaredField(descr.getName()); if(collectionfield.getGenericType() instanceof ParameterizedType){ ParameterizedType integerListType = (ParameterizedType) collectionfield.getGenericType(); Class<?> actualClazz = (Class<?>) integerListType.getActualTypeArguments()[0]; getBeanUtilsNestedFields(descr.getName(), actualClazz, nestedFieldNames); } else{ // or a complex custom type to get nested fields getBeanUtilsNestedFields(descr.getName(), descr.getPropertyType(), nestedFieldNames); } } else{ nestedFieldNames.add(prefix.concat(".").concat(descr.getDisplayName())); } } }


Otra forma de JacksonObjectMapper es convertValue ex:

ObjectMapper m = new ObjectMapper(); Map<String,Object> mappedObject = m.convertValue(myObject,Map.class);


Puede usar la introspección de JavaBeans para esto. Lea sobre la clase java.beans.Introspector :

public static Map<String, Object> introspect(Object obj) throws Exception { Map<String, Object> result = new HashMap<String, Object>(); BeanInfo info = Introspector.getBeanInfo(obj.getClass()); for (PropertyDescriptor pd : info.getPropertyDescriptors()) { Method reader = pd.getReadMethod(); if (reader != null) result.put(pd.getName(), reader.invoke(obj)); } return result; }

Gran advertencia: mi código trata solo con métodos getter; no encontrará campos desnudos. Para los campos, vea la respuesta altamente descafeinada. :-) (Probablemente quiera combinar los dos enfoques).


Utilice Apache Commons BeanUtils: http://commons.apache.org/beanutils/ .

Una implementación de Map for JavaBeans que utiliza introspección para obtener y poner propiedades en el bean:

Map<Object, Object> introspected = new org.apache.commons.beanutils.BeanMap(object);

Nota: a pesar de que la API devuelve Map<Object, Object> (desde 1.9.0), la clase real para las claves en el mapa devuelto es java.lang.String