All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jexx.bean.SimpleBeanInfo Maven / Gradle / Ivy

The newest version!
package jexx.bean;

import java.awt.*;
import java.beans.*;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.List;

public class SimpleBeanInfo implements BeanInfo {

    private final BeanInfo delegate;

    private final Set propertyDescriptors = new TreeSet<>(new PropertyDescriptorComparator());

    public SimpleBeanInfo(BeanInfo delegate) {
        this.delegate = delegate;
        for (PropertyDescriptor pd : delegate.getPropertyDescriptors()) {
            try {
                this.propertyDescriptors.add(pd instanceof IndexedPropertyDescriptor ?
                        new SimpleIndexedPropertyDescriptor((IndexedPropertyDescriptor) pd) :
                        new SimplePropertyDescriptor(pd));
            }
            catch (IntrospectionException ex) {
                // Probably simply a method that wasn't meant to follow the JavaBeans pattern...
            }
        }
        MethodDescriptor[] methodDescriptors = delegate.getMethodDescriptors();
        if (methodDescriptors != null) {
            for (Method method : findCandidateWriteMethods(methodDescriptors)) {
                try {
                    handleWriteMethod(method);
                }
                catch (IntrospectionException ex) {
                    // We're only trying to find candidates, can easily ignore extra ones here...
                }
            }
        }
    }

    /**
     * 找到候选写方法
     * @param methodDescriptors 方法描述集合
     */
    private java.util.List findCandidateWriteMethods(MethodDescriptor[] methodDescriptors) {
        List matches = new ArrayList<>();
        for (MethodDescriptor methodDescriptor : methodDescriptors) {
            Method method = methodDescriptor.getMethod();
            if (isWriteMethod(method)) {
                matches.add(method);
            }
        }
        // Sort non-void returning write methods to guard against the ill effects of
        // non-deterministic sorting of methods returned from Class#getDeclaredMethods
        // under JDK 7. See http://bugs.sun.com/view_bug.do?bug_id=7023180
        matches.sort((m1, m2) -> m2.toString().compareTo(m1.toString()));
        return matches;
    }

    /**
     * 是否为候选写方法
     * @param method 方法
     */
    public static boolean isWriteMethod(Method method) {
        String methodName = method.getName();
        Class[] parameterTypes = method.getParameterTypes();
        int nParams = parameterTypes.length;
        return (methodName.length() > 3 && methodName.startsWith("set") && Modifier.isPublic(method.getModifiers()) &&
                (!void.class.isAssignableFrom(method.getReturnType()) || Modifier.isStatic(method.getModifiers())) &&
                (nParams == 1 || (nParams == 2 && int.class == parameterTypes[0])));
    }

    /**
     * 处理写方法;
     * 方法参数长度是1时为PropertyDescriptor,是2时为IndexedPropertyDescriptor
     * @param method 写方法
     */
    private void handleWriteMethod(Method method) throws IntrospectionException {
        int nParams = method.getParameterCount();
        String propertyName = propertyNameFor(method);
        Class propertyType = method.getParameterTypes()[nParams - 1];
        PropertyDescriptor existingPd = findExistingPropertyDescriptor(propertyName, propertyType);
        if (nParams == 1) {
            if (existingPd == null) {
                this.propertyDescriptors.add(new SimplePropertyDescriptor(propertyName, null, method));
            }
            else {
                existingPd.setWriteMethod(method);
            }
        }
        else if (nParams == 2) {
            if (existingPd == null) {
                this.propertyDescriptors.add(
                        new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
            }
            else if (existingPd instanceof IndexedPropertyDescriptor) {
                ((IndexedPropertyDescriptor) existingPd).setIndexedWriteMethod(method);
            }
            else {
                this.propertyDescriptors.remove(existingPd);
                this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(
                        propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));
            }
        }
        else {
            throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method);
        }
    }

    /**
     * 方法对应的属性名称
     * @param method 方法
     */
    private String propertyNameFor(Method method) {
        return Introspector.decapitalize(method.getName().substring(3, method.getName().length()));
    }

    /**
     * 找到对应的属性描述
     * @param propertyName 属性名称
     * @param propertyType 属性类型
     */
    private PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class propertyType) {
        for (PropertyDescriptor pd : this.propertyDescriptors) {
            final Class candidateType;
            final String candidateName = pd.getName();
            if (pd instanceof IndexedPropertyDescriptor) {
                IndexedPropertyDescriptor ipd = (IndexedPropertyDescriptor) pd;
                candidateType = ipd.getIndexedPropertyType();
                if (candidateName.equals(propertyName) &&
                        (candidateType.equals(propertyType) || candidateType.equals(propertyType.getComponentType()))) {
                    return pd;
                }
            }
            else {
                candidateType = pd.getPropertyType();
                if (candidateName.equals(propertyName) &&
                        (candidateType.equals(propertyType) || propertyType.equals(candidateType.getComponentType()))) {
                    return pd;
                }
            }
        }
        return null;
    }

    @Override
    public BeanDescriptor getBeanDescriptor() {
        return this.delegate.getBeanDescriptor();
    }

    @Override
    public EventSetDescriptor[] getEventSetDescriptors() {
        return this.delegate.getEventSetDescriptors();
    }

    @Override
    public int getDefaultEventIndex() {
        return this.delegate.getDefaultEventIndex();
    }

    @Override
    public PropertyDescriptor[] getPropertyDescriptors() {
        return this.propertyDescriptors.toArray(new PropertyDescriptor[0]);
    }

    @Override
    public int getDefaultPropertyIndex() {
        return this.delegate.getDefaultPropertyIndex();
    }

    @Override
    public MethodDescriptor[] getMethodDescriptors() {
        return this.delegate.getMethodDescriptors();
    }

    @Override
    public BeanInfo[] getAdditionalBeanInfo() {
        return this.delegate.getAdditionalBeanInfo();
    }

    @Override
    public Image getIcon(int iconKind) {
        return this.delegate.getIcon(iconKind);
    }

    static class SimplePropertyDescriptor extends PropertyDescriptor {
        private Method readMethod;

        private Method writeMethod;

        private Class propertyType;

        private Class propertyEditorClass;

        public SimplePropertyDescriptor(PropertyDescriptor original) throws IntrospectionException {
            this(original.getName(), original.getReadMethod(), original.getWriteMethod());
            PropertyDescriptorUtil.copyNonMethodProperties(original, this);
        }

        public SimplePropertyDescriptor(String propertyName, Method readMethod, Method writeMethod)
                throws IntrospectionException {
            super(propertyName, null, null);
            this.readMethod = readMethod;
            this.writeMethod = writeMethod;
            this.propertyType = PropertyDescriptorUtil.findPropertyType(readMethod, writeMethod);
        }

        public Method getReadMethod() {
            return this.readMethod;
        }

        @Override
        public void setReadMethod(Method readMethod) {
            this.readMethod = readMethod;
        }

        @Override
        public Method getWriteMethod() {
            return this.writeMethod;
        }

        @Override
        public void setWriteMethod(Method writeMethod) {
            this.writeMethod = writeMethod;
        }

        @Override
        public Class getPropertyType() {
            if (this.propertyType == null) {
                try {
                    this.propertyType = PropertyDescriptorUtil.findPropertyType(this.readMethod, this.writeMethod);
                }
                catch (IntrospectionException ex) {
                    // Ignore, as does PropertyDescriptor#getPropertyType
                }
            }
            return this.propertyType;
        }

        @Override
        public Class getPropertyEditorClass() {
            return this.propertyEditorClass;
        }

        @Override
        public void setPropertyEditorClass(Class propertyEditorClass) {
            this.propertyEditorClass = propertyEditorClass;
        }

        @Override
        public boolean equals(Object other) {
            return (this == other || (other instanceof PropertyDescriptor &&
                    PropertyDescriptorUtil.equals(this, (PropertyDescriptor) other)));
        }

        @Override
        public String toString() {
            return String.format("%s[name=%s, propertyType=%s, readMethod=%s, writeMethod=%s]",
                    getClass().getSimpleName(), getName(), getPropertyType(), this.readMethod, this.writeMethod);
        }

    }

    static class SimpleIndexedPropertyDescriptor extends IndexedPropertyDescriptor {

        private Method readMethod;
        private Method writeMethod;
        private Class propertyType;
        private Method indexedReadMethod;
        private Method indexedWriteMethod;
        private Class indexedPropertyType;

        public SimpleIndexedPropertyDescriptor(IndexedPropertyDescriptor original) throws IntrospectionException {
            super(original.getName(), original.getReadMethod(), original.getWriteMethod(), original.getIndexedReadMethod(), original.getIndexedWriteMethod());
        }

        public SimpleIndexedPropertyDescriptor(String propertyName, Method readMethod, Method writeMethod, Method indexedReadMethod, Method indexedWriteMethod) throws IntrospectionException {
            super(propertyName, readMethod, writeMethod, indexedReadMethod, indexedWriteMethod);
            this.readMethod = readMethod;
            this.writeMethod = writeMethod;
            this.propertyType = PropertyDescriptorUtil.findPropertyType(readMethod, writeMethod);
            this.indexedReadMethod = indexedReadMethod;
            this.indexedWriteMethod = indexedWriteMethod;
            this.indexedPropertyType = PropertyDescriptorUtil.findIndexedPropertyType(propertyName, this.propertyType, indexedReadMethod, indexedWriteMethod);
        }

        @Override
        public Method getReadMethod() {
            return readMethod;
        }

        @Override
        public Method getWriteMethod() {
            return writeMethod;
        }

        @Override
        public Class getPropertyType() {
            if (this.propertyType == null) {
                try {
                    this.propertyType = PropertyDescriptorUtil.findPropertyType(this.readMethod, this.writeMethod);
                }
                catch (IntrospectionException ex) {
                    // Ignore, as does IndexedPropertyDescriptor#getPropertyType
                }
            }
            return this.propertyType;
        }

        @Override
        public Method getIndexedReadMethod() {
            return indexedReadMethod;
        }

        @Override
        public Method getIndexedWriteMethod() {
            return indexedWriteMethod;
        }

        @Override
        public Class getIndexedPropertyType() {
            if (this.indexedPropertyType == null) {
                try {
                    this.indexedPropertyType = PropertyDescriptorUtil.findIndexedPropertyType(
                            getName(), getPropertyType(), this.indexedReadMethod, this.indexedWriteMethod);
                }
                catch (IntrospectionException ex) {
                    // Ignore, as does IndexedPropertyDescriptor#getIndexedPropertyType
                }
            }
            return this.indexedPropertyType;
        }

        @Override
        public String toString() {
            return String.format("%s[name=%s, propertyType=%s, indexedPropertyType=%s, " +
                            "readMethod=%s, writeMethod=%s, indexedReadMethod=%s, indexedWriteMethod=%s]",
                    getClass().getSimpleName(), getName(), getPropertyType(), getIndexedPropertyType(),
                    this.readMethod, this.writeMethod, this.indexedReadMethod, this.indexedWriteMethod);
        }
    }

    static class PropertyDescriptorComparator implements Comparator {

        @Override
        public int compare(PropertyDescriptor desc1, PropertyDescriptor desc2) {
            String left = desc1.getName();
            String right = desc2.getName();
            for (int i = 0; i < left.length(); i++) {
                if (right.length() == i) {
                    return 1;
                }
                int result = left.getBytes()[i] - right.getBytes()[i];
                if (result != 0) {
                    return result;
                }
            }
            return left.length() - right.length();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy