Создать POJO и заполнить его с карты - PullRequest
0 голосов
/ 03 февраля 2020

Во время выполнения я хочу создать POJO с атрибутами, которые совпадают с ключами карты, и заполнить его значениями карты.
Я не знаю содержимого карты или как будет выглядеть POJO .
Пример -

Map<String,String> map = new HashMap<>();
map.add("attr1", obj1);
map.add("attr2", obj2);
...

На этой карте я хочу создать POJO-

class POJO
{
    String attr1;

    public void setAttr1(String attr1) {
        this.attr1 = attr1;
    }

    public String getAttr1() {
        return attr1;
    }

    String attr2;

    public void setAttr2(String attr2) {
        this.attr2 = attr2;
    }

    public String getAttr2() {
        return attr2;
    }

    .....
}

и наполни его тоже. Все это должно происходить во время выполнения. Что-то вроде -

Object object = getPopulatedPOJO(map)

или

Class type = getPOJOType(map);
Object object = type.newInstance();
object = getPopulatedPOJO(map)

Ответы [ 2 ]

1 голос
/ 03 февраля 2020

Это не окончательный ответ на вашу проблему. Но я надеюсь, что это дает направление, в котором вы можете продолжить. Обратите внимание, что это направление изменяет инструкции байт-кода во время выполнения и может вызвать сбои и сбои.

Вы можете использовать javassist, который является манипулятором байт-кода. Пожалуйста, смотрите их официальный сайт для получения дополнительной информации.

Две важные вещи, на которые стоит обратить внимание

  1. В Java, загрузчики нескольких классов могут сосуществовать, и каждый загрузчик классов создает свое собственное пространство имен. Разные загрузчики классов могут загружать разные файлы классов с одним и тем же именем класса

  2. JVM не позволяет динамически перезагружать класс. Как только загрузчик класса загружает класс, он не может перезагрузить измененную версию этого класса во время выполнения. Таким образом, вы не можете изменить определение класса после того, как JVM загрузит его. Тем не менее, JPDA (Java Platform Debugger Architecture) предоставляет ограниченные возможности для перезагрузки класса

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

  1. Создайте байт-код во время выполнения, напишите класс, используйте пользовательский загрузчик классов для создания вашего pojo из написанного класса. javassist может помочь вам в этом, но в данный момент это слишком сложно для меня.

  2. Используйте javassist, чтобы изменить существующий класс, и используйте отражение, чтобы установить значения.

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

  1. Добавьте javassist в ваш путь к классам. Если вы используете maven, добавьте следующую зависимость в ваш pom.xml.
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.21.0-GA</version>
</dependency>
  1. Создайте пустой пустой класс pojo, с которым вам нужно работать. Давайте назовем это Pojo.
package com.test;

public class Pojo {
   //Nothing in the source file.
}
Измените тело класса, добавив поля из HashMap. Вот пример того, как я это сделал, используя карту, которую вы дали.
        Map<String, String> map = new HashMap<String, String>();
        map.put("firstname", "John");
        map.put("lastname", "Doe");

        ClassPool cp = ClassPool.getDefault();

        CtClass cc = cp.get("com.test.Pojo");

        // Used for non-primitive data types. If primitive, use CtClass.<inttype, floattype, etc..>
        CtClass strClass = ClassPool.getDefault().get("java.lang.String");

        //Iterate and add all the fields as per the keys in the map
        Iterator<String> iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            CtField field = new CtField(strClass, key, cc);
            field.setModifiers(Modifier.PUBLIC);
            cc.addField(field);
        }

        // Instantiate from the updated class
        Class<Pojo> clazz = cc.toClass();
        Pojo newInstance = clazz.newInstance();

        //Use the map again to set the values using reflection.
        iterator = map.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            newInstance.getClass().getField(key).set(newInstance, map.get(key));
        }
newInstance является экземпляром Pojo, но поля добавляются на основе ключей карты и устанавливаются на основе значений на карте. Простой тест для печати newInstance с использованием jackson ObjectMapper дает следующее.
ObjectMapper objMapper = new ObjectMapper();
String writeValueAsString = objMapper.writeValueAsString(newInstance);
System.out.println(writeValueAsString);

{"firstname": "John", "lastname": "Doe"}

Надеюсь, это поможет.

РЕДАКТИРОВАТЬ

Если вы хотите добавить методы get / set, вы можете создавать методы, используя CtMethod в javassist. Однако вы можете получить к ним доступ только с помощью отражения, поскольку эти методы добавляются во время выполнения.

0 голосов
/ 03 февраля 2020

См. ответ в аналогичном вопросе, использование метода Джексона objectMapper.convertvalue представляется наиболее разумным.

...