如何使用Lambda表达式创建“ getter”

时间:2019-06-14 23:33:14

标签: java functional-programming

我在整个代码库UnsecureObject中都使用了一个对象。该对象是自动生成的,没有getter / setter,并且所有成员字段都是公共的。因此,可以通过执行以下操作来完成编辑:

unsecureObjInstance.firstName = "Jane";

由于许多原因(我可能不必在这里解释),这是不可取的。但是,对于我们的消息传递管道中不涉及的其他一些技术细节,需要使用此生成的类。

我希望利用团队中其他人编写的映射实用程序将此UnsecureObject转换为我正在编写的pojo。

一个正在运行的映射器的示例(带有两个带有getters / setter的普通类)的示例如下:

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

这会将PojoOne#name字段映射到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 :(得分:0)

我没有看到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();

    }

}