Как создать «получатель» с помощью лямбда-выражения - PullRequest
0 голосов
/ 15 июня 2019

У меня есть объект, используемый во всей моей кодовой базе, UnsecureObject.Этот объект создается автоматически без методов получения / установки, и все поля-члены являются открытыми.Поэтому редактирование выполняется следующим образом:

unsecureObjInstance.firstName = "Jane";

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

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

Пример маппера в действии (с двумя обычными классами w / getters / setters) будет выглядеть примерно так:

new MapperBuilder<>(PojoOne.class, PojoTwo.class)
      .from(PojoOne::getName).to(PojoTwo::getFirstName)
      .build();

Это сопоставит поле имени PojoOne # с PojoTwo #поле firstName.

Есть ли способ перевести это для ввода моего UnsecureObject здесь?Я пробовал что-то вроде следующего:

new MapperBuilder<>(UnsecureObject.class, SecureObject.class)
      .from(u -> u.firstName).to(SecureObject::getFirstName)
      .build();

Но получите ошибку здесь, что-то вроде 'u -> u.firstName' не может быть вызвано.

Итак, вопрос в следующем:

Есть ли способ по существу "создать" геттер на лету, используя этих открытых членов?Таким образом, в методе .from () я могу создать вызов, похожий на стандартный метод, который даст мой u.firstName?

Спасибо за помощь!

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

это примерно то, как выглядит класс MapperBuilder (попытка немного отредактировать, чтобы убрать специфичные для проекта оболочки / упростить)

/**
 * This class is used to convert between POJO getter method references to the corresponding field names.
 * @param <B> type
 */
public interface PojoProxy<B> {

  /**
   * Invokes the given getter method and returns information about the invocation.
   * @param getter the getter to invoke
   * @return information about the method invoked
   */
  <T> GetterInvocation<T> invokeGetter(Function<B, T> getter);

}

/**
 * Stores information about a method invocation.
 * @param <T> method return type
 */
public interface GetterInvocation<T> {

  public Class<T> getReturnType();

  public String getFieldName();

}


/**
 * A builder class to create {@link Mapper} instances.
 * @param <FROM> source type
 * @param <TO> target type
 */
public class MapperBuilder<FROM, TO> {

  private final Class<FROM> _fromClass;
  private final Class<TO> _toClass;
  private final PojoProxy<FROM> _fromProxy;
  private final PojoProxy<TO> _toProxy;

  public MapperBuilder(Class<FROM> fromClass, Class<TO> toClass) {
    _fromClass = fromClass;
    _toClass = toClass;

    //We will pretend there is an impl that provides the proxy.
    //Proxies wrap the from and to classes in order to get reflection information about their getter calls.
    _fromProxy = PojoProxy.of(fromClass);
    _toProxy = PojoProxy.of(toClass);
  }

  public <FROM_VALUE> ToFieldBuilder<FROM_VALUE> from(Function<FROM, FROM_VALUE> getter) {
    GetterInvocation<FROM_VALUE> methodInvocation = _fromProxy.invokeGetter(getter);
    return new ToFieldBuilder<>(methodInvocation.getFieldName(), methodInvocation.getReturnType());
  }

  public class ToFieldBuilder<FROM_VALUE> {

    private final String _fromFieldPath;
    private final Class<FROM_VALUE> _fromClass;

    public ToFieldBuilder(String fromFieldPath, Class<FROM_VALUE> fromClass) {
      _fromFieldPath = fromFieldPath;
      _fromClass = fromClass;
    }

    public <TO_VALUE> FromFieldBuilder<FROM_VALUE, TO_VALUE> to(Function<TO, TO_VALUE> getter) {
     //similar to above, but now using a FromFieldBuilder.
    }
  }

  public class FromFieldBuilder<FROM_VALUE, TO_VALUE> {

   //impl..
  }
}

1 Ответ

0 голосов
/ 15 июня 2019

Я не вижу MapperBuilder.from() деталей метода, вы можете попробовать эту реализацию MapperBuilder.java Function (getter) -> (BiConsumer) setter

public class MapperBuilder<S, D> {

    private final S src;
    private final D dest;

    public MapperBuilder(S src, Class<D> dest) {
        this.src = src;
        try {
            this.dest = dest.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("Required default constructor for: " + dest);
        }
    }

    //getter  - function to get value from source instance
    //setter  - biConsumer to set value to destination instance
    //example - map(SrcClass::getSrcValue, DestClass::setDestValue)
    public <V> MapperBuilder<S, D> map(Function<S, V> getter, BiConsumer<D, V> setter) {
        setter.accept(dest, getter.apply(src));
        return this;
    }

    public D build() {
        return dest;
    }

}

SrcClass.java некоторый источниккласс:

public class SrcClass {

    private String srcValue;

    public String getSrcValue() {
        return srcValue;
    }

    public void setSrcValue(String srcValue) {
        this.srcValue = srcValue;
    }

}

DestClass.java некоторый класс назначения:

package com.example.demo;

public class DestClass {

    private String destValue;

    public String getDestValue() {
        return destValue;
    }

    public void setDestValue(String destValue) {
        this.destValue = destValue;
    }

}

DemoApplication.java демонстрация:

public class DemoApplication {

    public static void main(String[] args) {

        SrcClass src = new SrcClass();
        src.setSrcValue("someValue");

        DestClass dest = new MapperBuilder<>(src, DestClass.class)
                .map(SrcClass::getSrcValue, DestClass::setDestValue)
                // map another fields
                .build();

        // for your UnsecureObject case
        UnsecureObject unsecureObject = new MapperBuilder<>(src, UnsecureObject.class)
                .map(SrcClass::getSrcValue, 
                        (unsecure, srcValue) -> unsecure.unsecureValue = srcValue)
                .build();

    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...