重新创建(通用)成员并通过Java反射填充/分配字段成员

时间:2018-12-14 20:25:30

标签: java generics reflection

我有一组带有任意数量的非自定义成员的类-仅仅是基元,包装等。其中一些可以用"ami-000bd263d51e443f2",100,5,10,20,40,30,5 进行注释,以便进行不同的处理。所有类型都实现@Encrypted

我正在创建两个Envelope(基于给定类型),存储“字段名称”(作为键)和“字段值”(作为值)。

问题是,当我尝试根据Map重新创建类型时。这是我到目前为止的内容:

Map

有什么线索可以解决这个问题吗?我可以使用任何图书馆。


我唯一的限制是当前类型没有设置器-我无法添加这些设置器,而且我使用的是Java 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(); } } }

例如,这是一个示例:

8

3 个答案:

答案 0 :(得分:1)

如果这些字段是私有的,我相信您需要使它们可访问。在您的try块中:

Field f = FieldUtils.getField(type.getClass(), fieldName);
f.setAccessible(true);
f.set(type, fieldValue);

答案 1 :(得分:1)

要扩展我的评论,请尝试以下操作(未经测试):

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();
    }
  }
}

答案 2 :(得分:1)

您可能希望通过构造函数传递通用对象(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;
    }
    ...
}

然后在T build()方法中使用Class::instance

public T build() {

    try {
        final T result = clazz.newInstance();
        ...
    } ...
}