Java BeanUtils不适用于链条设置器
e、 g 我的输出: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
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);