Как преобразовать объект Java (бин) в пары ключ-значение (и наоборот)? - PullRequest
88 голосов
/ 11 апреля 2009

Скажем, у меня есть очень простой Java-объект, который имеет только некоторые свойства getXXX и setXXX. Этот объект используется только для обработки значений, в основном для записи или для карты с типом (и производительностью). Мне часто приходится конвертировать этот объект в пары ключ-значение (строки или безопасный тип) или преобразовывать пары ключ-значение в этот объект.

Что лучше, чем размышление или написание кода для этого преобразования вручную,

Примером может быть отправка этого объекта через jms без использования типа ObjectMessage (или преобразование входящего сообщения в правильный тип объекта).

Ответы [ 22 ]

170 голосов
/ 11 января 2010

Много потенциальных решений, но давайте добавим еще одно. Используйте Джексон (библиотека обработки JSON), чтобы выполнить преобразование "json-less", например:

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

( эта запись в блоге имеет еще несколько примеров)

Вы можете конвертировать любые совместимые типы: совместимые, что означает, что если вы действительно конвертировали из типа в JSON и из этого JSON в тип результата, записи будут совпадать (при правильной настройке можно просто игнорировать нераспознанные).

Хорошо работает для случаев, которые можно ожидать, включая Карты, Списки, массивы, примитивы, бобовые POJO.

50 голосов
/ 11 апреля 2009

Всегда есть apache commons beanutils , но, конечно, он использует отражение под капотом

8 голосов
/ 11 апреля 2009

Генерация кода была бы единственным способом, о котором я могу думать. Лично я получил решение для многократного использования отражений (если только эта часть кода не критична для производительности) Использование JMS звучит как излишнее (дополнительная зависимость, и это даже не то, для чего она предназначена). Кроме того, он, вероятно, использует отражение под капотом.

7 голосов
/ 15 октября 2012

Это метод для преобразования объекта Java в карту

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

Вот как это назвать

   Test test = new Test()
   Map<String, Object> map = ConvertObjectToMap(test);
4 голосов
/ 04 ноября 2015

С Java 8 вы можете попробовать это:

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 "";
                        }
                    }));
}
3 голосов
/ 11 апреля 2009

JSON , например, с использованием XStream + Jettison, это простой текстовый формат с парами ключ-значение. Он поддерживается, например, брокером сообщений Apache ActiveMQ JMS для обмена объектами Java с другими платформами / языками.

3 голосов
/ 02 июня 2009

Лучшее решение - использовать Dozer. Вам просто нужно что-то вроде этого в файле картографа:

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

И все, Дозер позаботится обо всем остальном !!!

URL документации Dozer

3 голосов
/ 13 мая 2012

Просто используя отражение и 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;
}
3 голосов
/ 15 июня 2013

Использование juffrou-рефлекса BeanWrapper. Это очень эффективно.

Вот как вы можете преобразовать бин в карту:

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

Я сам разработал Джуффру. Это открытый исходный код, так что вы можете использовать его и изменять. И если у вас есть какие-либо вопросы по этому поводу, я буду более чем рад ответить.

Приветствия

Carlos

3 голосов
/ 23 октября 2014

При использовании Spring также можно использовать Spring Integration объект-карта-преобразователь. Вероятно, не стоит добавлять Spring как зависимость только для этого.

Для документации, поиск "Трансформатор объекта в карту" на http://docs.spring.io/spring-integration/docs/4.0.4.RELEASE/reference/html/messaging-transformation-chapter.html

По сути, он пересекает весь граф объектов, достижимый из объекта, заданного в качестве входных данных, и создает карту из всех полей примитивного типа / String на объектах. Может быть настроен на вывод:

  • плоская карта: {rootObject.someField = Joe, rootObject.leafObject.someField = Jane} или
  • структурированная карта: {someField = Joe, leafObject = {someField = Jane}}.

Вот пример с их страницы:

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
}

Вывод будет:

{person.name = George, person.child.name = Дженна, person.child.nickNames [0] = Бимбо. , , и т.д.}

Также имеется обратный трансформатор.

...