001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.granite.util;
019    
020    import java.lang.reflect.Method;
021    
022    
023    public class PropertyDescriptor {
024            
025            private String name;
026        private Method getter;
027        private Method setter;
028    
029        public PropertyDescriptor(String propertyName, Method getter, Method setter) {
030            this.name = propertyName;
031            setReadMethod(getter);
032            setWriteMethod(setter);
033        }
034    
035        public PropertyDescriptor(String propertyName, Class<?> beanClass) {
036            this.name = propertyName;
037            try {
038                setReadMethod(beanClass, createDefaultMethodName(propertyName, "is"));
039            } 
040            catch (Exception e) {
041                setReadMethod(beanClass, createDefaultMethodName(propertyName, "get"));
042            }
043    
044            setWriteMethod(beanClass, createDefaultMethodName(propertyName, "set"));
045        }
046        
047        public String getName() {
048            return this.name;
049        }
050    
051        public void setWriteMethod(Method setter) {
052            this.setter = setter;
053        }
054    
055        public void setReadMethod(Method getter) {
056            this.getter = getter;
057        }
058    
059        public Method getWriteMethod() {
060            return setter;
061        }
062    
063        public Method getReadMethod() {
064            return getter;
065        }
066    
067        @Override
068        public boolean equals(Object object) {
069            if (!(object instanceof PropertyDescriptor))
070                    return false;
071    
072            PropertyDescriptor pd = (PropertyDescriptor)object;
073            if (!((this.getter == null && pd.getter == null) 
074                            || (this.getter != null && this.getter.equals(pd.getter))))
075                    return false;
076            
077            if (!((this.setter == null && pd.setter == null) 
078                            || (this.setter != null && this.setter.equals(pd.setter))))
079                    return false;
080            
081            return this.getPropertyType() == pd.getPropertyType();
082        }
083    
084        @Override
085        public int hashCode() {
086            int hashCode = getter != null ? getter.hashCode() : 0;
087            if (setter != null)
088                    hashCode = hashCode*31 + setter.hashCode();
089            if (getPropertyType() != null)
090                    hashCode = hashCode*31 + getPropertyType().hashCode();
091            return hashCode;
092        }
093    
094        public Class<?> getPropertyType() {
095            if (getter != null)
096                return getter.getReturnType();
097            if (setter != null) {
098                Class<?>[] parameterTypes = setter.getParameterTypes();
099                return parameterTypes[0];
100            }
101            return null;
102        }
103    
104        private String createDefaultMethodName(String propertyName, String prefix) {
105            return prefix + propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
106        }
107    
108        private void setReadMethod(Class<?> beanClass, String getterName) {
109            try {
110                Method readMethod = beanClass.getMethod(getterName, new Class[] {});
111                setReadMethod(readMethod);
112            } 
113            catch (Exception e) {
114                throw new RuntimeException("Introspection exception", e);
115            }
116        }
117    
118        private void setWriteMethod(Class<?> beanClass, String setterName) {
119            Method writeMethod = null;
120            try {
121                if (getter != null) {
122                    writeMethod = beanClass.getMethod(setterName, new Class[] { getter.getReturnType() });
123                } 
124                else {
125                    Class<?> clazz = beanClass;
126                    Method[] methods = null;
127                    while (clazz != null && writeMethod == null) {
128                        methods = clazz.getDeclaredMethods();
129                        for (Method method : methods) {
130                            if (setterName.equals(method.getName())) {
131                                if (method.getParameterTypes().length == 1) {
132                                    writeMethod = method;
133                                    break;
134                                }
135                            }
136                        }
137                        clazz = clazz.getSuperclass();
138                    }
139                }
140            } 
141            catch (Exception e) {
142                throw new RuntimeException("Introspection exception", e);
143            }
144            if (writeMethod == null)
145                throw new RuntimeException("Could not find setter for property " + name);
146            
147            setWriteMethod(writeMethod);
148        }
149    }