valor son obtener objetos lista las cuales conclusion collection colecciones arreglos java reflection collections javabeans

son - ¿Cómo convertir un objeto Java(bean) a pares clave-valor(y viceversa)?



lista de objetos java (21)

¡Debería escribir un servicio de transformación genérico! Use genéricos para mantenerlo libre de tipo (para que pueda convertir cada objeto a clave => valor y viceversa).

¿Qué campo debería ser la clave? Obtenga ese campo del bean y agregue cualquier otro valor no transitorio en un mapa de valores.

El camino de regreso es bastante fácil. Lea la clave (x) y escriba al principio la clave y luego cada entrada de la lista a un nuevo objeto.

¡Puede obtener los nombres de las propiedades de un frijol con los beanutils de apache commons !

Digamos que tengo un objeto java muy simple que solo tiene algunas propiedades getXXX y setXXX. Este objeto se usa solo para manejar valores, básicamente un registro o un mapa de tipo seguro (y de rendimiento). A menudo necesito ocultar este objeto a pares de valores clave (ya sea cadenas o tipo seguro) o convertir pares de valores clave a este objeto.

Aparte de la reflexión o el código de escritura manual para hacer esta conversión, ¿cuál es la mejor manera de lograr esto?

Un ejemplo podría ser enviar este objeto a través de jms, sin utilizar el tipo ObjectMessage (o convertir un mensaje entrante al tipo correcto de objeto).


Al usar Spring, también se puede usar Spring Integration object-to-map-transformer. Probablemente no valga la pena agregar Spring como una dependencia solo por esto.

Para la documentación, busque "Transformador de objeto a mapa" en http://docs.spring.io/spring-integration/docs/4.0.4.RELEASE/reference/html/messaging-transformation-chapter.html

Básicamente, atraviesa todo el gráfico de objetos accesible desde el objeto dado como entrada, y produce un mapa a partir de todos los campos de tipo primitivo / Cadena en los objetos. Se puede configurar para generar:

  • un mapa plano: {rootObject.someField = Joe, rootObject.leafObject.someField = Jane} o
  • un mapa estructurado: {someField = Joe, leafObject = {someField = Jane}}.

Aquí hay un ejemplo de su página:

public class Parent{ private Child child; private String name; // setters and getters are omitted } public class Child{ private String name; private List<String> nickNames; // setters and getters are omitted }

La salida será:

{person.name = George, person.child.name = Jenna, person.child.nickNames [0] = Bimbo. . . etc}

Un transformador inverso también está disponible.


Con Java 8 puedes probar esto:

public Map<String, Object> toKeyValuePairs(Object instance) { return Arrays.stream(Bean.class.getDeclaredMethods()) .collect(Collectors.toMap( Method::getName, m -> { try { Object result = m.invoke(instance); return result != null ? result : ""; } catch (Exception e) { return ""; } })); }


Con la ayuda de la biblioteca de Jackson, pude encontrar todas las propiedades de clase de tipo String / integer / double, y los valores respectivos en una clase Map. ( sin usar reflexiones api! )

TestClass testObject = new TestClass(); com.fasterxml.jackson.databind.ObjectMapper m = new com.fasterxml.jackson.databind.ObjectMapper(); Map<String,Object> props = m.convertValue(testObject, Map.class); for(Map.Entry<String, Object> entry : props.entrySet()){ if(entry.getValue() instanceof String || entry.getValue() instanceof Integer || entry.getValue() instanceof Double){ System.out.println(entry.getKey() + "-->" + entry.getValue()); } }


Este es un método para convertir un objeto Java en un Mapa

public static Map<String, Object> ConvertObjectToMap(Object obj) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<?> pomclass = obj.getClass(); pomclass = obj.getClass(); Method[] methods = obj.getClass().getMethods(); Map<String, Object> map = new HashMap<String, Object>(); for (Method m : methods) { if (m.getName().startsWith("get") && !m.getName().startsWith("getClass")) { Object value = (Object) m.invoke(obj); map.put(m.getName().substring(3), (Object) value); } } return map; }

Así es como llamarlo

Test test = new Test() Map<String, Object> map = ConvertObjectToMap(test);


La generación de código sería la única otra forma en que se me ocurre. Personalmente, obtuve una solución de reflexión generalmente reutilizable (a menos que esa parte del código sea absolutamente crítica para el rendimiento). El uso de JMS suena como overkill (dependencia adicional, y eso ni siquiera es lo que significa). Además, probablemente también usa la reflexión debajo del capó.


La mejor solución es usar Dozer. Solo necesitas algo como esto en el archivo mapeador:

<mapping map-id="myTestMapping"> <class-a>org.dozer.vo.map.SomeComplexType</class-a> <class-b>java.util.Map</class-b> </mapping>

Y eso es todo, ¡Dozer se ocupa del resto!

URL de documentación de Dozer


Mi JavaDude Bean Annotation Processor genera código para hacer esto.

http://javadude.googlecode.com

Por ejemplo:

@Bean( createPropertyMap=true, properties={ @Property(name="name"), @Property(name="phone", bound=true), @Property(name="friend", type=Person.class, kind=PropertyKind.LIST) } ) public class Person extends PersonGen {}

Lo anterior genera la superclase PersonGen que incluye un método createPropertyMap () que genera un Mapa para todas las propiedades definidas usando @Bean.

(Tenga en cuenta que estoy cambiando ligeramente la API para la próxima versión - el atributo de anotación será defineCreatePropertyMap = true)


Muchas soluciones posibles, pero agreguemos solo una más. Use Jackson (JSON processing lib) para hacer la conversión "json-less", como:

ObjectMapper m = new ObjectMapper(); Map<String,Object> props = m.convertValue(myBean, Map.class); MyBean anotherBean = m.convertValue(props, MyBean.class);

( esta entrada de blog tiene algunos ejemplos más)

Básicamente, puede convertir cualquier tipo compatible: compatible, lo que significa que si convirtió de tipo a JSON, y de ese tipo JSON a resultado, las entradas coincidirían (si está configurado correctamente también puede simplemente ignorar las no reconocidas).

Funciona bien para los casos que cabría esperar, incluidos mapas, listas, matrices, primitivos, POJOs similares a frijoles.


Otra forma posible es aquí.

BeanWrapper ofrece funcionalidad para establecer y obtener valores de propiedad (individualmente o en bloque), obtener descriptores de propiedad y consultar propiedades para determinar si son legibles o escribibles.

Company c = new Company(); BeanWrapper bwComp = BeanWrapperImpl(c); bwComp.setPropertyValue("name", "your Company");


Por supuesto, es el medio de conversión más simple posible, ¡sin conversión!

en lugar de usar variables privadas definidas en la clase, haga que la clase contenga solo un HashMap que almacena los valores para la instancia.

Luego, sus getters y setters regresan y establecen valores dentro y fuera del HashMap, y cuando es hora de convertirlo en un mapa, ¡voilá! - ya es un mapa.

Con un poco de magia de AOP, incluso podría mantener la inflexibilidad inherente en un bean al permitirle usar getters y setters específicos para cada nombre de valores, sin tener que escribir realmente los getters y setters individuales.


Probablemente tarde a la fiesta. Puede usar Jackson y convertirlo en un objeto Properties. Esto es adecuado para clases anidadas y si desea la clave en el para abc = valor.

JavaPropsMapper mapper = new JavaPropsMapper(); Properties properties = mapper.writeValueAsProperties(sct); Map<Object, Object> map = properties;

si quieres un sufijo, solo hazlo

SerializationConfig config = mapper.getSerializationConfig() .withRootName("suffix"); mapper.setConfig(config);

necesito agregar esta dependencia

<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-properties</artifactId> </dependency>


Puede usar las propiedades del recopilador de filtro de flujo java 8,

public Map<String, Object> objectToMap(Object obj) { return Arrays.stream(YourBean.class.getDeclaredMethods()) .filter(p -> !p.getName().startsWith("set")) .filter(p -> !p.getName().startsWith("getClass")) .filter(p -> !p.getName().startsWith("setClass")) .collect(Collectors.toMap( d -> d.getName().substring(3), m -> { try { Object result = m.invoke(obj); return result; } catch (Exception e) { return ""; } }, (p1, p2) -> p1) ); }



Si no desea codificar las llamadas a cada getter y setter, la reflexión es la única forma de llamar a estos métodos (pero no es difícil).

¿Se puede refactorizar la clase en cuestión para usar un objeto Properties para contener los datos reales, y dejar que cada getter y setter simplemente invoquen get / set? Entonces tienes una estructura adecuada para lo que quieres hacer. Incluso hay métodos para guardarlos y cargarlos en la forma de clave-valor.


Si realmente quieres rendimiento, puedes ir a la ruta de generación de código.

Puedes hacer esto en tu lugar haciendo tu propio reflejo y construyendo una mezcla en AspectJ ITD.

O puede usar Spring Roo y hacer un complemento de Spring Roo . Su complemento Roo hará algo similar a lo anterior, pero estará disponible para todos los que utilicen Spring Roo y no tendrá que usar Anotaciones en tiempo de ejecución.

He hecho ambas cosas. La gente miente en Spring Roo pero realmente es la generación de código más completa para Java.


Si se trata de un árbol de objetos simple para la asignación de listas de valores clave, donde la clave puede ser una descripción de ruta punteada desde el elemento raíz del objeto hasta la hoja que se inspecciona, es bastante obvio que una conversión de árbol a una lista clave-valor es comparable a Objeto de mapeo xml. Cada elemento dentro de un documento XML tiene una posición definida y se puede convertir en una ruta. Por lo tanto, tomé XStream como una herramienta de conversión básica y estable y reemplacé las partes jerárquicas de controlador y escritor con una implementación propia. XStream también viene con un mecanismo de seguimiento de ruta básico que, al combinarse con los otros dos, conduce estrictamente a una solución adecuada para la tarea.



Simplemente usando la reflexión y Groovy:

def Map toMap(object) { return object?.properties.findAll{ (it.key != ''class'') }.collectEntries { it.value == null || it.value instanceof Serializable ? [it.key, it.value] : [it.key, toMap(it.value)] } } def toObject(map, obj) { map.each { def field = obj.class.getDeclaredField(it.key) if (it.value != null) { if (field.getType().equals(it.value.class)){ obj."$it.key" = it.value }else if (it.value instanceof Map){ def objectFieldValue = obj."$it.key" def fieldValue = (objectFieldValue == null) ? field.getType().newInstance() : objectFieldValue obj."$it.key" = toObject(it.value,fieldValue) } } } return obj; }


Usa juffrou-reflect reflect''s BeanWrapper. Es muy eficiente.

Aquí es cómo puedes transformar un frijol en un mapa:

public static Map<String, Object> getBeanMap(Object bean) { Map<String, Object> beanMap = new HashMap<String, Object>(); BeanWrapper beanWrapper = new BeanWrapper(BeanWrapperContext.create(bean.getClass())); for(String propertyName : beanWrapper.getPropertyNames()) beanMap.put(propertyName, beanWrapper.getValue(propertyName)); return beanMap; }

Desarrollé Juffrou yo mismo. Es de código abierto, por lo que puede usarlo y modificarlo. Y si tiene alguna pregunta al respecto, estaré más que feliz de responder.

Aclamaciones

Carlos


JSON , por ejemplo, usando XStream + Jettison, es un formato de texto simple con pares de valores clave. Es compatible, por ejemplo, con el intermediario de mensajes JMS de Apache ActiveMQ para el intercambio de objetos Java con otras plataformas / idiomas.