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

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

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

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

Ответы [ 22 ]

2 голосов
/ 04 мая 2016

Вы можете использовать свойства сборщика фильтра потока 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)
            );
}
2 голосов
/ 11 апреля 2009

Вы можете использовать фреймворк Joda:

http://joda.sourceforge.net/

и воспользуйтесь JodaProperties. Однако это означает, что вы создаете bean-компоненты определенным образом и реализуете определенный интерфейс. Тем не менее, он позволяет вам возвращать карту свойств из определенного класса без отражения. Пример кода здесь:

http://pbin.oogly.co.uk/listings/viewlistingdetail/0e78eb6c76d071b4e22bbcac748c57

2 голосов
/ 31 июля 2014

Конечно, существует абсолютное простейшее средство преобразования - никакого преобразования вообще!

вместо использования частных переменных, определенных в классе, сделайте так, чтобы класс содержал только HashMap, в котором хранятся значения для экземпляра.

Тогда ваши геттеры и сеттеры возвращают и устанавливают значения в и из HashMap, а когда пришло время конвертировать его в карту, вуаля! - это уже карта.

С небольшим количеством волшебства AOP вы могли бы даже поддерживать негибкость, присущую bean-компоненту, позволяя вам по-прежнему использовать геттеры и сеттеры, специфичные для каждого имени значения, без необходимости писать отдельные геттеры и сеттеры.

2 голосов
/ 14 апреля 2009

Если вы не хотите жестко кодировать вызовы для каждого метода получения и установки, отражение является единственным способом вызова этих методов (но это не сложно).

Можете ли вы провести рефакторинг рассматриваемого класса, чтобы использовать объект Properties для хранения реальных данных, и позволить каждому получателю и установщику просто вызывать get / set для него? Тогда у вас есть структура, хорошо подходящая для того, что вы хотите сделать. Есть даже методы для сохранения и загрузки их в форме ключ-значение.

1 голос
/ 23 марта 2017

С помощью библиотеки Джексона я смог найти все свойства класса типа String / integer / double и соответствующие значения в классе Map. ( без использования отражений 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());
    }
}
1 голос
/ 13 апреля 2009

Мой JavaNude Bean Annotation Processor генерирует код для этого.

http://javadude.googlecode.com

Например:

@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 {}

Выше генерируется суперкласс PersonGen, который включает метод createPropertyMap (), который генерирует Map для всех свойств, определенных с помощью @ Bean.

(Обратите внимание, что я слегка изменяю API для следующей версии - атрибут аннотации будет defineCreatePropertyMap = true)

1 голос
/ 01 июля 2012

Еще один возможный путь здесь.

BeanWrapper предлагает функциональность для установки и получения значений свойств (индивидуально или навалом), получить дескрипторы свойств и запросить свойства, чтобы определить, являются ли они доступны для чтения или записи.

Company c = new Company();
 BeanWrapper bwComp = BeanWrapperImpl(c);
 bwComp.setPropertyValue("name", "your Company");
1 голос
/ 31 января 2018

Возможно, опоздал на вечеринку. Вы можете использовать Джексона и преобразовать его в объект Properties. Это подходит для вложенных классов, и если вы хотите ввести ключ для a.b.c = value.

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

если вам нужен суффикс, просто наберите

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

нужно добавить эту зависимость

<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-properties</artifactId>
</dependency>
1 голос
/ 22 сентября 2011

Если речь идет о простом сопоставлении дерева значений ключа с деревом объектов, где ключ может быть точечным описанием пути от корневого элемента объекта до проверяемого листа, то вполне очевидно, что преобразование дерева в список значений ключа сравнимо с сопоставлением объекта с XML. Каждый элемент в документе XML имеет определенную позицию и может быть преобразован в путь. Поэтому я взял XStream в качестве базового и стабильного инструмента преобразования и заменил части иерархического драйвера и модуля записи собственной реализацией. XStream также поставляется с базовым механизмом отслеживания пути, который - в сочетании с двумя другими - приводит к тому, что решение подходит для этой задачи.

1 голос
/ 14 апреля 2009

Вам следует написать универсальный Сервис трансформации! Используйте дженерики, чтобы сохранить его тип свободным (чтобы вы могли преобразовать каждый объект в ключ => значение и обратно).

В каком поле должен быть ключ? Получите это поле из компонента и добавьте любое другое непереходное значение в карту значений.

Обратный путь довольно легкий. Прочитайте ключ (x) и напишите сначала ключ, а затем каждую запись в списке обратно в новый объект.

Вы можете получить имена свойств bean-компонента с помощью apache commons beanutils !

...