Повторно создайте (универсальный) элемент и заполните / назначьте элемент (ы) поля с помощью отражения Java - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть набор классов с любым количеством нестандартных членов - только примитивы, оболочки и т. Д .;некоторые из них могут быть помечены @Encrypted для обработки по-разному.Все типы реализуют Envelope.

Я создаю два Map s (на основе заданного типа), сохраняя «имя поля» (как ключ) и «значение поля» (какзначение).

Проблема в том, что я пытаюсь воссоздать типы снова на основе Map s.Это то, что я имею до сих пор:

import io.shido.domain.Envelope;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.util.Map;

public final class Factory<T extends Envelope> {
  private final Map<String, Object> regularMembers;

  private final Map<String, Object> secureMembers;

  public Factory(final Map<String, Object> regularMembers, final Map<String, Object> secureMembers) {
    this.regularMembers = regularMembers;
    this.secureMembers = secureMembers;
  }

  public T build() {
    try {
      final ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass(); // This doesn't work >:(
      final Class<T> type = (Class<T>) superClass.getActualTypeArguments()[0];
      final T result = type.newInstance();
      regularMembers.forEach((fieldName, fieldValue) -> assign(result, fieldName, fieldValue));
      secureMembers.forEach((fieldName, fieldValue) -> assign(result, fieldName, fieldValue));
      return result;
    } catch (final Exception e) {
      logger.error("Cannot build type based on input parameters due to:", e);
      throw new IllegalStateException(e.toString());
    }
  }

  private void assign(final T type, final String fieldName, final Object fieldValue) {
    try {
      FieldUtils.getField(type.getClass(), fieldName).set(type, fieldValue);
    } catch (final IllegalAccessException e) {
      e.printStackTrace();
    }
  }
}

Есть какие-нибудь подсказки, как подойти к этому?Я могу использовать любую библиотеку.


Единственное ограничение, которое у меня есть, это то, что у текущих типов нет сеттеров - и я не могу их добавить, и я использую Java 8.

Например, это пример:

public final class ExampleType implements Envelope {
  @Encrypted
  private String first;

  private String second;

  @Encrypted
  private String third;

  public ExampleType() { }

  public ExampleType(final String first, final String second, final String third) {
    this.first = first;
    this.second = second;
    this.third = third;
  }

  public String getFirst() { return first; }

  public String getSecond() { return second; }

  public String getThird() { return third; }
}

Ответы [ 3 ]

0 голосов
/ 14 декабря 2018

Чтобы расширить мой комментарий, попробуйте что-то вроде этого (не проверено):

import io.shido.domain.Envelope;
import org.apache.commons.lang3.reflect.FieldUtils;

import java.util.Map;

public final class Factory<T extends Envelope> {
  private final Class<T> clazz;

  private final Map<String, Object> regularMembers;

  private final Map<String, Object> secureMembers;

  public Factory(final Class<T> clazz, final Map<String, Object> regularMembers, final Map<String, Object> secureMembers) {
    this.clazz = clazz;
    this.regularMembers = regularMembers;
    this.secureMembers = secureMembers;
  }

  public T build() {
    try {
      final T result = clazz.newInstance();
      regularMembers.forEach((fieldName, fieldValue) -> assign(result, fieldName, fieldValue));
      secureMembers.forEach((fieldName, fieldValue) -> assign(result, fieldName, fieldValue));
      return result;
    } catch (final Exception e) {
      logger.error("Cannot build type based on input parameters due to:", e);
      throw new IllegalStateException(e.toString());
    }
  }

  private void assign(final T type, final String fieldName, final Object fieldValue) {
    try {
      FieldUtils.getField(type.getClass(), fieldName).set(type, fieldValue);
    } catch (final IllegalAccessException e) {
      e.printStackTrace();
    }
  }
}
0 голосов
/ 14 декабря 2018

Возможно, вы захотите передать класс универсального объекта (Class<T>) через конструктор и использовать его непосредственно для его создания.

public final class Factory<T extends Envelope> {

    private Class<T> clazz;
    // maps omitted

    public Factory(Class<T> clazz, Map<String, Object> rm, Map<String, Object> sm) {
        this.clazz = clazz;
        this.regularMembers = rm;
        this.secureMembers = sm;
    }
    ...
}

И затем используйте Class::instance в методе T build():

public T build() {

    try {
        final T result = clazz.newInstance();
        ...
    } ...
}
0 голосов
/ 14 декабря 2018

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

Field f = FieldUtils.getField(type.getClass(), fieldName);
f.setAccessible(true);
f.set(type, fieldValue);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...