首页 > 解决方案 > 如何使用 lambda 表达式创建“getter”

问题描述

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

unsecureObjInstance.firstName = "Jane";

出于许多我可能不必在这里解释的原因,这是不可取的。但是对于我们的消息传递管道的一些其他技术细节,我不会深入讨论,因此需要使用这个生成的类。

我有一个愿望是利用我团队中其他人编写的映射实用程序将其转换UnsecureObject为我正在编写的 pojo。

实际中的映射器示例(具有两个普通类,带有 getter/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..
  }
}

标签: javafunctional-programming

解决方案


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

    }

}

推荐阅读