1

我有一个简单的实体用户。

public class User {

  String name;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

}

和他对应的DTO

public class UsuarioDTO {

  String name;

  String getName(){
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

}

我想实现如下所示的目标,以避免使用多类变压器。

@Dto(entity = "Usuario")
public class UsuarioDTO {

  @BasicElement(name = "name")
  String name;

  String getName(){
    return this.name;
  }

  public void setName(String name) {
    this.name = name;
  }

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface BasicElement {

  String name();

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Dto {

  String entity() default "";

}

使用这个示例类,我可以做到:

public class Transformer {

  public static void main(String[] args) {
    UserDTO usuarioDTO = new UserDTO("Gabriel");

    Class<UserDTO> obj = UserDTO.class;

    if (obj.isAnnotationPresent(Dto.class)) {

      Dto annotation = obj.getAnnotation(Dto.class);

      Class<?> clazz;
      try {
        clazz = Class.forName(annotation.entity());
        Constructor<?> constructor = clazz.getConstructor();
        Object instance = constructor.newInstance();

        for (Field originField : UserDTO.class.getDeclaredFields()) {
          originField.setAccessible(true);
          if (originField.isAnnotationPresent(BasicElement.class)) {
            BasicElement basicElement = originField.getAnnotation(BasicElement.class);
            Field destinationField = instance.getClass().getDeclaredField(basicElement.name());
            destinationField.setAccessible(true);
            destinationField.set(instance, originField.get(usuarioDTO));

          }
        }
        System.out.println(((User) instance).getName());

      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }

    }
  }
}

但这会很昂贵,因为在每个转换中都会消耗注释。

Byte-buddy 可以读取注释并创建一个类转换器,其反编译代码如下所示:

public class TransformerImpl implements ITransformer{
  public Object toEntity(Object dto){
    User user = new User();
    user.setName(dto.getName());
  }
}

更新: @Rafael Winterhalter,是这样的吗?

public class Transformer<D,E> {

    List<Field> dtoFields = new ArrayList<Field>();

    Constructor<D> dtoConstructor;

    List<Field> entityFields = new ArrayList<Field>();

    Constructor<E> entityConstructor;

    public Transformer(Class<D> dtoClass){
        try {
            Dto annotation = dtoClass.getAnnotation(Dto.class);
            Class<E> entityClass = (Class<E>) annotation.entity();
            //entityConstructor = entityClass.getConstructor();
            entityConstructor = entityClass.getDeclaredConstructor();
            entityConstructor.setAccessible(true);
            dtoConstructor = dtoClass.getConstructor();
            dtoConstructor.setAccessible(true);
            lookupFields(entityClass, dtoClass);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void lookupFields(Class<E> entityClass, Class<D> dtoClass) throws NoSuchFieldException {
        for (Field dtoField : dtoClass.getDeclaredFields()) {
            if (dtoField.isAnnotationPresent(BasicElement.class)) {
                BasicElement basicElement = dtoField.getAnnotation(BasicElement.class);
                String entityFieldName = (basicElement.name().equals("")) ? dtoField.getName() : basicElement.name();
                Field entityField = entityClass.getDeclaredField(entityFieldName);
                dtoField.setAccessible(true);
                entityField.setAccessible(true);
                dtoFields.add(dtoField);
                entityFields.add(entityField);
            }
        }
    }

    public E toEntity(D dto) throws ReflectiveOperationException {
        E entity = entityConstructor.newInstance();
        for (int i = 0; i < entityFields.size(); i++){
            Field destination = entityFields.get(i);
            Field origin = dtoFields.get(i);
            destination.set(entity, origin.get(dto));
        }
        return entity;
    }

    public D toDto(E entity) throws ReflectiveOperationException {
        D dto = dtoConstructor.newInstance();
        for (int i = 0; i < entityFields.size(); i++){
            Field origin = entityFields.get(i);
            Field destination = dtoFields.get(i);
            destination.set(dto, origin.get(entity));
        }
        return dto;
    }
}
4

1 回答 1

2

回答你的问题:是的,有可能。您可以要求 Byte Buddy 为您创建实例,ITransformer您可以在其中实现唯一的方法来做您想做的事。但是,您需要为此实现自己的Implementation实例。

但是,我不建议您这样做。我通常告诉用户 Byte Buddy 不应该用于性能工作,对于大多数用例来说,这是真的。您的用例就是其中之一。

如果您实现了类,则必须为任何映射缓存这些类。否则,类生成成本将占很大比例。相反,您宁愿维护一个转换器来缓存反射 API 的对象(反射查找是您操作的昂贵部分,反射调用不是那么成问题)并重用以前查找的值。通过这种方式,您可以在不将代码生成作为应用程序的另一个(复杂)元素拖入的情况下获得性能。

于 2015-09-23T13:09:48.353 回答