BeanUtils not works for chain setter

后端 未结 3 977
你的背包
你的背包 2021-01-04 19:25

e.g.

class tester
{
    @Test
    public void testBeanUtils() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException
    {
        S         


        
3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-01-04 20:05

    In my project we use chained accessors across the board, so setting chain=false was not an option. I ended up writing my own introspector, which is similar to the one recommended by @mthielcke, and may be registered in the same way.

    Introspector

    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 fluent through Lombok
     * {@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 Lombok 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 getLombokMethods(IntrospectionContext context) {
            Map 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 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 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].*");
        }
    
    }
    

    Registration

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

提交回复
热议问题