Приведение объектов через отражение в Java - PullRequest
0 голосов
/ 05 сентября 2011

Я пишу метод десериализатора, который выглядит следующим образом:

public <T> T deserialize(Object[] result, String[] fields, Class<T> type);

Так что в основном я буду передаваться в массиве результатов, который является всеми объектами, и в типе класса T, который мне нуженпреобразовать данные в массиве в типы в данном классе, создать новый класс типа T и вернуть его.Поля String[] - это имена полей, соответствующие данным в результате Object[].Имена полей будут соответствовать классу T.

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

например,

result = ["Mike", "London", 28];
fields = ["name", "location", "age" ];

Класс T =

public class GivenClass{

  private String name;
  private String location;
  private Integer age;

  public GivenClass(String name, String location, Integer age){
    this.name = name;
    this.location = location;
    this.age = age;
  }
}

Ответы [ 4 ]

3 голосов
/ 05 сентября 2011

Класс реализации

static class GivenClass {

    private String name;
    private String location;
    private Integer age;

    public GivenClass(String name, String location, Integer age) {
        this.name = name;
        this.location = location;
        this.age = age;
    }

    public GivenClass(Map<String, Object> data) throws Exception {
        for (Field f : GivenClass.class.getDeclaredFields())
            f.set(this, data.get(f.getName()));
    }

    public Map<String, Object> serialize() throws Exception {
        Map<String, Object> fields = new HashMap<String, Object>();
        for (Field f : GivenClass.class.getDeclaredFields()) 
            fields.put(f.getName(), f.get(this));
        return fields;
    }

    @Override
    public String toString() {
        return "age=" + age + ", location=" + location + ", name=" + name;
    }
}

Пример:

public static void main(String[] args) throws Exception {

    GivenClass o1 = new GivenClass("Mike", "London", 28);

    Map<String, Object> serialized = o1.serialize();

    GivenClass o2 = new GivenClass(serialized);
    System.out.println(o2.toString());
}

Выход:

age=28, location=London, name=Mike
1 голос
/ 05 сентября 2011

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

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

Подход, который я использую, заключается в использовании соглашения о том, что параметры конструктора находятся в том же порядке, что и поля. Вы также можете предположить, что тип параметров конструктора и типы полей совпадают. ;)

Я бы также использовал примитивы вместо оберток всякий раз, когда это возможно. Используйте int, если вы не хотите, чтобы null был допустимым параметром. Если это так, подумайте о том, как вы хотите это представить. Для текста я обычно использую пустые строки или пустое поле для null или NaN в зависимости от контекста.

0 голосов
/ 05 сентября 2011

Как говорит Питер Лоури, приведение не преобразует строку в целое число.

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

См. Следующий пример:

import org.apache.commons.beanutils.BeanUtils;

public class BeanUtilsTest {
    public static class Obj {
        private int number;
        private String string;

        public void setNumber(int number) {
            this.number = number;
        }
        public void setString(String string) {
            this.string = string;
        }

        public String toString() {
            return "number=" + number + " string=" + string;
        }
    }

    public static void main(String args[]) throws Exception {
        String[] values = new String[] { "1", "two" };
        String[] properties = new String[] { "number", "string" };

        Obj obj = new Obj();

        for (int i = 0; i < properties.length; i++) {
            BeanUtils.setProperty(obj, properties[i], values[i]);
        }

        System.out.println("obj=" + obj);
    }
}

В результате получается:

obj=number=1 string=two

Обратите внимание, что в приведенном выше примере есть только сеттеры, но он все еще работает.

0 голосов
/ 05 сентября 2011

Проблема в том, что в Java невозможно получить имена параметров конструктора.

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

public GivenClass() {
  super();
}

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

Но я думаю, что было бы намного проще аннотировать ваш конструктор, а затем извлекать информацию аннотаций в вашем deserialize методе. В этом случае вам не нужно извлекать поля и создавать пустой конструктор.

Пример:

Вам нужно создать аннотацию, подобную этой:

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property
{
    String value();
}

И тогда вы можете использовать его в своем конструкторе следующим образом:

public GivenClass(@Property("name") String name, @Property("location") String location, @Property("age") Integer age) {
  // ...
}
...