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
018package org.granite.util;
019
020import java.lang.reflect.Method;
021
022
023public 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}