Java BeanUtils不适用于链条设置器

Java BeanUtils不适用于链条设置器,java,reflection,chaining,apache-commons-beanutils,lombok,Java,Reflection,Chaining,Apache Commons Beanutils,Lombok,e、 g 我的输出: class tester { @Test public void testBeanUtils() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { Stranger stranger = new Stranger(); BeanUtils.setProperty(stranger,"name","wener

e、 g

我的输出:

class tester
{
    @Test
    public void testBeanUtils() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
    {
        Stranger stranger = new Stranger();
        BeanUtils.setProperty(stranger,"name","wener");
        BeanUtils.setProperty(stranger,"xname","xwener");
        BeanUtils.setProperty(stranger,"yname","ywener");

        System.out.println(stranger);
    }
    @Data// lombok annotation generate all setter and getter
    public static class Stranger
    {
        @Accessors(chain = true)// generate chained setter
        String name;
        String xname;
        String yname;

        public Stranger setYname(String yname)// no lombok, still not work
        {
            this.yname = yname;
            return this;
        }
    }
}
这个怎么了?链条安装工是件好事。 有什么建议吗

编辑

再次回到这个问题。这次我无法删除
访问器链
。 现在,我使用
commons-lang3
来实现

TestValues.Stranger(name=null, xname=xwener, yname=null)

对于那些有同样问题的人。

这很简单:
小海狸
非常奇怪,
内省者
也很奇怪,它使用:

虽然声明了一些异常,但似乎不存在要设置的属性。最终的罪魁祸首是内省者,它只是塞特的空虚

我会称之为设计上的破坏,但YMMV。这是一个古老的类,在那些黑暗的时代,流畅的接口还没有发明出来。用于禁用链接



更重要的是:。获取它并使用调试器(它已经在您的IDE中)自己查找它(如果它不起作用,请随时询问,只需再努力一点即可)。

您可以使用FluentPropertyBeanSintrospector实现:

“BeanTransectt接口的一个实现,它可以检测fluent API场景中使用的属性的写入方法。”


在我的项目中,我们全面使用链式访问器,因此设置
chain=false
不是一个选项。最后我写了我自己的内省,它类似于@mthielcke推荐的内省,并且可能以同样的方式注册

内省者

PropertyUtils.addBeanIntrospector(new FluentPropertyBeanIntrospector());
BeanUtils.setProperty( this.o, "property", "value" );

也许这里可以用BeanHelper。它似乎使用了一个流畅的界面。坦克,已经禁用链,等待这应该是解决方案。它实际上解决了这个问题。
PropertyUtils.addBeanIntrospector(new FluentPropertyBeanIntrospector());
BeanUtils.setProperty( this.o, "property", "value" );
import org.apache.commons.beanutils.BeanIntrospector;
import org.apache.commons.beanutils.IntrospectionContext;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Stream;

import lombok.extern.slf4j.Slf4j;

/**
 * Allows {@link org.apache.commons.beanutils.BeanUtils#copyProperties(Object, Object)} to copy properties across beans whose
 * properties have been made <b>fluent</b> through <a href="https://projectlombok.org/">Lombok</a>
 * {@link lombok.experimental.Accessors}, {@link lombok.Setter} and {@link lombok.Getter} annotations.
 *
 * @author izilotti
 */
@Slf4j
public class LombokPropertyBeanIntrospector implements BeanIntrospector {

    /**
     * Performs introspection. This method scans the current class's methods for property write and read methods which have been
     * created by the <a href="https://projectlombok.org/">Lombok</a> annotations.
     *
     * @param context The introspection context.
     */
    @Override
    public void introspect(final IntrospectionContext context) {
        getLombokMethods(context).forEach((propertyName, methods) -> {
            if (methods[0] != null && methods[1] != null) {
                final PropertyDescriptor pd = context.getPropertyDescriptor(propertyName);
                try {
                    if (pd == null) {
                        PropertyDescriptor descriptor = new PropertyDescriptor(propertyName, methods[1], methods[0]);
                        context.addPropertyDescriptor(descriptor);
                    }
                } catch (final IntrospectionException e) {
                    log.error("Error creating PropertyDescriptor for {}. Ignoring this property.", propertyName, e);
                }
            }
        });
    }

    private Map<String, Method[]> getLombokMethods(IntrospectionContext context) {
        Map<String, Method[]> lombokPropertyMethods = new HashMap<>(); // property name, write, read
        Stream.of(context.getTargetClass().getMethods())
                .filter(this::isNotJavaBeanMethod)
                .forEach(method -> {
                    if (method.getReturnType().isAssignableFrom(context.getTargetClass()) && method.getParameterCount() == 1) {
                        log.debug("Found mutator {} with parameter {}", method.getName(), method.getParameters()[0].getName());
                        final String propertyName = propertyName(method);
                        addWriteMethod(lombokPropertyMethods, propertyName, method);
                    } else if (!method.getReturnType().equals(Void.TYPE) && method.getParameterCount() == 0) {
                        log.debug("Found accessor {} with no parameter", method.getName());
                        final String propertyName = propertyName(method);
                        addReadMethod(lombokPropertyMethods, propertyName, method);
                    }
                });
        return lombokPropertyMethods;
    }

    private void addReadMethod(Map<String, Method[]> lombokPropertyMethods, String propertyName, Method readMethod) {
        if (!lombokPropertyMethods.containsKey(propertyName)) {
            Method[] writeAndRead = new Method[2];
            lombokPropertyMethods.put(propertyName, writeAndRead);
        }
        lombokPropertyMethods.get(propertyName)[1] = readMethod;
    }

    private void addWriteMethod(Map<String, Method[]> lombokPropertyMethods, String propertyName, Method writeMethod) {
        if (!lombokPropertyMethods.containsKey(propertyName)) {
            Method[] writeAndRead = new Method[2];
            lombokPropertyMethods.put(propertyName, writeAndRead);
        }
        lombokPropertyMethods.get(propertyName)[0] = writeMethod;
    }

    private String propertyName(final Method method) {
        final String methodName = method.getName();
        return (methodName.length() > 1) ? Introspector.decapitalize(methodName) : methodName.toLowerCase(Locale.ENGLISH);
    }

    private boolean isNotJavaBeanMethod(Method method) {
        return !isGetter(method) || isSetter(method);
    }

    private boolean isGetter(Method method) {
        if (Modifier.isPublic(method.getModifiers()) && method.getParameterTypes().length == 0) {
            if (method.getName().matches("^get[A-Z].*") && !method.getReturnType().equals(Void.TYPE)) {
                return true;
            }
            return method.getName().matches("^is[A-Z].*") && method.getReturnType().equals(Boolean.TYPE);
        }
        return false;
    }

    private boolean isSetter(Method method) {
        return Modifier.isPublic(method.getModifiers())
                && method.getReturnType().equals(Void.TYPE)
                && method.getParameterTypes().length == 1
                && method.getName().matches("^set[A-Z].*");
    }

}
PropertyUtils.addBeanIntrospector(new LombokPropertyBeanIntrospector());
BeanUtils.copyProperties(dest, origin);