001package net.gdface.utils;
002
003import java.beans.IntrospectionException;
004import java.beans.PropertyDescriptor;
005import java.lang.reflect.Method;
006
007/**
008 * 重写{@link #getWriteMethod()}方法,允许返回类型不为void的write方法
009 * @author guyadong
010 *
011 */
012public class LenientDecoratorOfDescriptor extends PropertyDescriptor {
013        private final PropertyDescriptor descriptor;
014
015        private LenientDecoratorOfDescriptor(PropertyDescriptor descriptor) throws IntrospectionException {
016                super(descriptor.getName(), 
017                                classOf(descriptor),
018                                readMethodNameOf(descriptor),
019                                writeMethodNameOf(descriptor));
020                this.descriptor = descriptor;
021        }
022        private static String readMethodNameOf(PropertyDescriptor descriptor){
023                Method m = descriptor.getReadMethod();
024                return null == m ? null : m.getName();
025        }
026        private static String writeMethodNameOf(PropertyDescriptor descriptor){
027                Method m = descriptor.getWriteMethod();
028                return null == m ? null : m.getName();
029        }
030        private static Class<?> classOf(PropertyDescriptor descriptor){
031                try {
032                        Method m =  (Method) internalFindMethod(descriptor.getClass(),"getClass0");
033                        m.setAccessible(true);
034                        return (Class<?>) m.invoke(descriptor);
035                } catch (NullPointerException e) {
036                        throw e;
037                }catch (RuntimeException e) {
038                        throw e;
039                } catch (Exception e) {
040                        throw new RuntimeException(e);
041                } 
042        }
043    /**
044     * Returns a String which capitalizes the first letter of the string.
045     */
046    private static String capitalize(String name) {
047        if (name == null || name.length() == 0) {
048            return name;
049        }
050        return name.substring(0, 1).toUpperCase() + name.substring(1);
051    }
052    @Override
053        public synchronized Method getWriteMethod() {
054                Method writeMethod = super.getWriteMethod();
055                if (writeMethod == null) {
056                        Class<?> cls = classOf(this);
057                        String writeMethodName = "set" + capitalize(getName());
058
059                        Class<?> type = getPropertyType();
060                        Class<?>[] args = (type == null) ? null : new Class[] { type };
061                        try {
062                                writeMethod = cls.getMethod(writeMethodName, args);
063                                setWriteMethod(writeMethod);
064                        } catch (NoSuchMethodException e) {
065                        } catch (IntrospectionException ex) {
066                                // fall through
067                        }
068                }
069                return writeMethod;
070        }
071        public PropertyDescriptor origin() {
072                return descriptor;
073        }
074        public static LenientDecoratorOfDescriptor toDecorator(PropertyDescriptor descriptor){
075                if(descriptor instanceof LenientDecoratorOfDescriptor){
076                        return (LenientDecoratorOfDescriptor)descriptor;
077                }
078                try {
079                        return new LenientDecoratorOfDescriptor(descriptor);
080                } catch (IntrospectionException e) {
081                        throw new RuntimeException(e);
082                }
083        }
084    /**
085     * Internal support for finding a target methodName with a given
086     * parameter list on a given class.
087     */
088    private static Method internalFindMethod(Class<?> start, String methodName,Class<?> ...args) {
089
090        Method method = null;
091
092        for (Class<?> cl = start; cl != null && cl.getDeclaringClass() != Object.class && method == null; cl = cl.getSuperclass()) {
093                try {
094                        method = cl.getDeclaredMethod(methodName, args);
095                } catch (NoSuchMethodException e) {
096                } 
097        }
098        return method;
099    }
100
101}