Скажем, у меня есть очень простой объект java, который имеет только некоторые свойства getXXX и setXXX. Этот объект используется только для обработки значений, в основном записи или типобезопасной (и производительной) карты. Мне часто нужно преобразовать этот объект в пары ключ-значение (строковые или типобезопасные) или преобразовать из пар ключ-значение в этот объект.
Как лучше всего добиться этого, кроме отражения или написания кода вручную для этого преобразования?
Примером может быть отправка этого объекта через jms без использования типа ObjectMessage (или преобразование входящего сообщения в объект правильного типа).
java
reflection
collections
javabeans
Шахбаз
источник
источник
java.beans.Introspector
.getBeanInfo()
. Он встроен прямо в JDK.Ответы:
Всегда есть beanutils apache commons, но, конечно, он использует отражение под капотом
источник
java.beans
зависимости, сильно ограниченные платформой. Подробнее см. Соответствующий вопрос .Возможных решений много, но давайте добавим еще одно. Используйте Jackson (библиотека обработки JSON) для преобразования "без json", например:
ObjectMapper m = new ObjectMapper(); Map<String,Object> props = m.convertValue(myBean, Map.class); MyBean anotherBean = m.convertValue(props, MyBean.class);
(в этой записи блога есть еще несколько примеров)
Вы можете в основном преобразовать любые совместимые типы: совместимые, что означает, что если вы преобразовали из типа в JSON, а из этого JSON в тип результата, записи будут совпадать (при правильной настройке также можно просто игнорировать нераспознанные).
Хорошо работает для ожидаемых случаев, включая карты, списки, массивы, примитивы, объекты POJO типа bean.
источник
BeanUtils
хорошо, но не может обрабатывать массивы и перечисленияГенерация кода была бы единственным другим способом, о котором я могу думать. Лично я получил обычно многоразовое решение для отражения (если только эта часть кода не является абсолютно критичной для производительности). Использование JMS звучит как излишество (дополнительная зависимость, и это даже не то, для чего она предназначена). Кроме того, он, вероятно, также использует отражение под капотом.
источник
Это метод преобразования объекта 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);
источник
Наверное, опоздал на вечеринку. Вы можете использовать Jackson и преобразовать его в объект Properties. Это подходит для вложенных классов, и если вам нужен ключ для abc = value.
JavaPropsMapper mapper = new JavaPropsMapper(); Properties properties = mapper.writeValueAsProperties(sct); Map<Object, Object> map = properties;
если вам нужен суффикс, просто сделайте
SerializationConfig config = mapper.getSerializationConfig() .withRootName("suffix"); mapper.setConfig(config);
нужно добавить эту зависимость
источник
С 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 ""; } })); }
источник
JSON , например с использованием XStream + Jettison, представляет собой простой текстовый формат с парами ключ-значение. Он поддерживается, например, брокером сообщений JMS Apache ActiveMQ для обмена объектами Java с другими платформами / языками.
источник
Просто используя отражение и 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; }
источник
Используйте BeanWrapper juffrou- Reflection. Это очень эффективно.
Вот как вы можете превратить bean-компонент в карту:
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; }
Я сам разработал Джуффро. Это открытый исходный код, поэтому вы можете использовать его и изменять. И если у вас есть какие-либо вопросы по этому поводу, я буду более чем счастлив ответить.
Ура
Карлос
источник
При использовании Spring можно также использовать преобразователь объектов-карт Spring Integration. Вероятно, не стоит добавлять Spring в качестве зависимости только для этого.
Чтобы найти документацию, выполните поиск по запросу «Преобразователь объектов в карту» на http://docs.spring.io/spring-integration/docs/4.0.4.RELEASE/reference/html/messaging-transformation-chapter.html.
По сути, он просматривает весь граф объектов, доступный из объекта, указанного в качестве входных данных, и создает карту из всех полей примитивного типа / String на объектах. Его можно настроить для вывода:
Вот пример с их страницы:
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 }
Результат будет:
Также доступен обратный трансформатор.
источник
Вы можете использовать фреймворк Joda:
http://joda.sourceforge.net/
и воспользуйтесь JodaProperties. Однако это оговаривает, что вы создаете bean-компоненты определенным образом и реализуете определенный интерфейс. Тем не менее, он позволяет вам возвращать карту свойств из определенного класса без отражения. Пример кода здесь:
http://pbin.oogly.co.uk/listings/viewlistingdetail/0e78eb6c76d071b4e22bbcac748c57
источник
Если вы не хотите жестко кодировать вызовы каждого получателя и сеттера, отражение - единственный способ вызвать эти методы (но это несложно).
Можете ли вы реорганизовать рассматриваемый класс, чтобы использовать объект Properties для хранения фактических данных, и позволить каждому получателю и сеттеру просто вызывать для него get / set? Тогда у вас есть структура, хорошо подходящая для того, чем вы хотите заниматься. Существуют даже способы их сохранения и загрузки в форме "ключ-значение".
источник
Лучшее решение - использовать Dozer. Вам просто нужно что-то вроде этого в файле mapper:
<mapping map-id="myTestMapping"> <class-a>org.dozer.vo.map.SomeComplexType</class-a> <class-b>java.util.Map</class-b> </mapping>
И все, обо всем остальном Dozer позаботится !!!
URL-адрес документации по бульдозеру
источник
Конечно, существует самый простой способ преобразования - никакого преобразования!
вместо использования частных переменных, определенных в классе, сделайте так, чтобы класс содержал только HashMap, в котором хранятся значения для экземпляра.
Затем ваши геттеры и сеттеры возвращаются и устанавливают значения в HashMap и из него, и когда приходит время преобразовать его в карту, вуаля! - это уже карта.
Приложив немного «волшебства» АОП, вы даже сможете сохранить негибкость, присущую bean-компоненту, позволив вам по-прежнему использовать геттеры и сеттеры, специфичные для каждого имени значения, без необходимости фактически писать отдельные геттеры и сеттеры.
источник
Вы можете использовать свойства сборщика фильтров потока 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) ); }
источник
Мой процессор аннотаций JavaDude Bean генерирует код для этого.
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 (), который генерирует карту для всех свойств, определенных с помощью @Bean.
(Обратите внимание, что я немного меняю API для следующей версии - атрибут аннотации будет defineCreatePropertyMap = true)
источник
Вам следует написать универсальную службу преобразования! Используйте дженерики, чтобы он оставался свободным от типа (чтобы вы могли преобразовать каждый объект в key => value и обратно).
Какое поле должно быть ключевым? Получите это поле из bean-компонента и добавьте любое другое непреходящее значение в карту значений.
Обратный путь довольно прост. Прочтите ключ (x) и запишите сначала ключ, а затем каждую запись списка обратно в новый объект.
Вы можете получить имена свойств bean-компонента с помощью beanutils apache commons !
источник
Если вам действительно нужна производительность, вы можете пойти по пути генерации кода.
Вы можете сделать это самостоятельно, выполнив собственное отражение и создав миксин AspectJ ITD.
Или вы можете использовать Spring Roo и создать надстройку Spring Roo . Ваш аддон Roo будет делать что-то подобное вышеупомянутому, но будет доступен всем, кто использует Spring Roo, и вам не нужно использовать аннотации времени выполнения.
Я сделал и то, и другое. Люди гадят на Spring Roo, но на самом деле это наиболее полная генерация кода для Java.
источник
Еще один возможный способ здесь.
BeanWrapper предлагает функциональные возможности для установки и получения значений свойств (индивидуально или сразу), получения дескрипторов свойств и запроса свойств, чтобы определить, доступны ли они для чтения или записи.
Company c = new Company(); BeanWrapper bwComp = BeanWrapperImpl(c); bwComp.setPropertyValue("name", "your Company");
источник
Если дело доходит до простого сопоставления дерева объектов со списком значений ключа, где ключ может быть описанием пути, разделенного точками, от корневого элемента объекта до проверяемого листа, довольно очевидно, что преобразование дерева в список значений ключей сопоставимо с объект для сопоставления XML. Каждый элемент в XML-документе имеет определенную позицию и может быть преобразован в путь. Поэтому я взял XStream в качестве основного и стабильного инструмента преобразования и заменил иерархические драйверы и компоненты записи собственной реализацией. XStream также поставляется с базовым механизмом отслеживания пути, который в сочетании с двумя другими строго приводит к решению, подходящему для данной задачи.
источник
С помощью библиотеки Джексона я смог найти все свойства класса типа 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()); } }
источник
Используя Gson,
object
в JsonПреобразовать Json в карту
retMap = new Gson().fromJson(new Gson().toJson(object), new TypeToken<HashMap<String, Object>>() {}.getType() );
источник
Мы можем использовать библиотеку Джексона, чтобы легко преобразовать объект Java в карту.
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.3</version> </dependency>
При использовании в проекте Android вы можете добавить jackson в build.gradle вашего приложения следующим образом:
implementation 'com.fasterxml.jackson.core:jackson-core:2.9.8' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.9.8' implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8'
Пример реализации
public class Employee { private String name; private int id; private List<String> skillSet; // getters setters } public class ObjectToMap { public static void main(String[] args) { ObjectMapper objectMapper = new ObjectMapper(); Employee emp = new Employee(); emp.setName("XYZ"); emp.setId(1011); emp.setSkillSet(Arrays.asList("python","java")); // object -> Map Map<String, Object> map = objectMapper.convertValue(emp, Map.class); System.out.println(map); } }
Выход:
{имя = XYZ, id = 1011, навыки = [python, java]}
источник