1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.beans; 19 20import java.lang.reflect.Constructor; 21import java.lang.reflect.Method; 22import java.lang.reflect.Modifier; 23import java.util.Vector; 24import org.apache.harmony.beans.internal.nls.Messages; 25 26public class PropertyDescriptor extends FeatureDescriptor { 27 private Method getter; 28 29 private Method setter; 30 31 private Class<?> propertyEditorClass; 32 33 private boolean constrained; 34 35 private boolean bound; 36 37 public PropertyDescriptor(String propertyName, Class<?> beanClass, String getterName, 38 String setterName) throws IntrospectionException { 39 super(); 40 if (beanClass == null) { 41 throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$ 42 } 43 if (propertyName == null || propertyName.length() == 0) { 44 throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$ 45 } 46 this.setName(propertyName); 47 this.setDisplayName(propertyName); 48 if (setterName != null) { 49 if (hasMethod(beanClass, setterName)) { 50 setWriteMethod(beanClass, setterName); 51 } else { 52 throw new IntrospectionException(Messages.getString("beans.20")); //$NON-NLS-1$ 53 } 54 } 55 if (getterName != null) { 56 if (hasMethod(beanClass, getterName)) { 57 setReadMethod(beanClass, getterName); 58 } else { 59 throw new IntrospectionException(Messages.getString("beans.1F")); //$NON-NLS-1$ 60 } 61 } 62 } 63 64 public PropertyDescriptor(String propertyName, Method getter, Method setter) 65 throws IntrospectionException { 66 super(); 67 if (propertyName == null || propertyName.length() == 0) { 68 throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$ 69 } 70 this.setName(propertyName); 71 this.setDisplayName(propertyName); 72 setWriteMethod(setter); 73 setReadMethod(getter); 74 } 75 76 public PropertyDescriptor(String propertyName, Class<?> beanClass) 77 throws IntrospectionException { 78 String getterName; 79 String setterName; 80 if (beanClass == null) { 81 throw new IntrospectionException(Messages.getString("beans.03")); //$NON-NLS-1$ 82 } 83 if (propertyName == null || propertyName.length() == 0) { 84 throw new IntrospectionException(Messages.getString("beans.04")); //$NON-NLS-1$ 85 } 86 this.setName(propertyName); 87 this.setDisplayName(propertyName); 88 getterName = createDefaultMethodName(propertyName, "is"); //$NON-NLS-1$ 89 if (hasMethod(beanClass, getterName)) { 90 setReadMethod(beanClass, getterName); 91 } else { 92 getterName = createDefaultMethodName(propertyName, "get"); //$NON-NLS-1$ 93 if (hasMethod(beanClass, getterName)) { 94 setReadMethod(beanClass, getterName); 95 } 96 } 97 setterName = createDefaultMethodName(propertyName, "set"); //$NON-NLS-1$ 98 if (hasMethod(beanClass, setterName)) { 99 setWriteMethod(beanClass, setterName); 100 } 101 if (getter == null && setter == null) { 102 throw new IntrospectionException(Messages.getString("beans.01", propertyName)); //$NON-NLS-1$ 103 } 104 } 105 106 public void setWriteMethod(Method setter) throws IntrospectionException { 107 if (setter != null) { 108 int modifiers = setter.getModifiers(); 109 if (!Modifier.isPublic(modifiers)) { 110 throw new IntrospectionException(Messages.getString("beans.05")); //$NON-NLS-1$ 111 } 112 Class<?>[] parameterTypes = setter.getParameterTypes(); 113 if (parameterTypes.length != 1) { 114 throw new IntrospectionException(Messages.getString("beans.06")); //$NON-NLS-1$ 115 } 116 Class<?> parameterType = parameterTypes[0]; 117 Class<?> propertyType = getPropertyType(); 118 if (propertyType != null && !propertyType.equals(parameterType)) { 119 throw new IntrospectionException(Messages.getString("beans.07")); //$NON-NLS-1$ 120 } 121 } 122 this.setter = setter; 123 } 124 125 public void setReadMethod(Method getter) throws IntrospectionException { 126 if (getter != null) { 127 int modifiers = getter.getModifiers(); 128 if (!Modifier.isPublic(modifiers)) { 129 throw new IntrospectionException(Messages.getString("beans.0A")); //$NON-NLS-1$ 130 } 131 Class<?>[] parameterTypes = getter.getParameterTypes(); 132 if (parameterTypes.length != 0) { 133 throw new IntrospectionException(Messages.getString("beans.08")); //$NON-NLS-1$ 134 } 135 Class<?> returnType = getter.getReturnType(); 136 if (returnType.equals(Void.TYPE)) { 137 throw new IntrospectionException(Messages.getString("beans.33")); //$NON-NLS-1$ 138 } 139 Class<?> propertyType = getPropertyType(); 140 if ((propertyType != null) && !returnType.equals(propertyType)) { 141 throw new IntrospectionException(Messages.getString("beans.09")); //$NON-NLS-1$ 142 } 143 } 144 this.getter = getter; 145 } 146 147 public Method getWriteMethod() { 148 return setter; 149 } 150 151 public Method getReadMethod() { 152 return getter; 153 } 154 155 @Override 156 public boolean equals(Object object) { 157 boolean result = (object != null && object instanceof PropertyDescriptor); 158 if (result) { 159 PropertyDescriptor pd = (PropertyDescriptor) object; 160 boolean gettersAreEqual = (this.getter == null) && (pd.getReadMethod() == null) 161 || (this.getter != null) && (this.getter.equals(pd.getReadMethod())); 162 boolean settersAreEqual = (this.setter == null) && (pd.getWriteMethod() == null) 163 || (this.setter != null) && (this.setter.equals(pd.getWriteMethod())); 164 boolean propertyTypesAreEqual = this.getPropertyType() == pd.getPropertyType(); 165 boolean propertyEditorClassesAreEqual = this.getPropertyEditorClass() == pd 166 .getPropertyEditorClass(); 167 boolean boundPropertyAreEqual = this.isBound() == pd.isBound(); 168 boolean constrainedPropertyAreEqual = this.isConstrained() == pd.isConstrained(); 169 result = gettersAreEqual && settersAreEqual && propertyTypesAreEqual 170 && propertyEditorClassesAreEqual && boundPropertyAreEqual 171 && constrainedPropertyAreEqual; 172 } 173 return result; 174 } 175 176 public void setPropertyEditorClass(Class<?> propertyEditorClass) { 177 this.propertyEditorClass = propertyEditorClass; 178 } 179 180 public Class<?> getPropertyType() { 181 Class<?> result = null; 182 if (getter != null) { 183 result = getter.getReturnType(); 184 } else if (setter != null) { 185 Class<?>[] parameterTypes = setter.getParameterTypes(); 186 result = parameterTypes[0]; 187 } 188 return result; 189 } 190 191 public Class<?> getPropertyEditorClass() { 192 return propertyEditorClass; 193 } 194 195 public void setConstrained(boolean constrained) { 196 this.constrained = constrained; 197 } 198 199 public void setBound(boolean bound) { 200 this.bound = bound; 201 } 202 203 public boolean isConstrained() { 204 return constrained; 205 } 206 207 public boolean isBound() { 208 return bound; 209 } 210 211 boolean hasMethod(Class<?> beanClass, String methodName) { 212 Method[] methods = findMethods(beanClass, methodName); 213 return (methods.length > 0); 214 } 215 216 String createDefaultMethodName(String propertyName, String prefix) { 217 String result = null; 218 if (propertyName != null) { 219 String bos = propertyName.substring(0, 1).toUpperCase(); 220 String eos = propertyName.substring(1, propertyName.length()); 221 result = prefix + bos + eos; 222 } 223 return result; 224 } 225 226 Method[] findMethods(Class<?> aClass, String methodName) { 227 Method[] allMethods = aClass.getMethods(); 228 Vector<Method> matchedMethods = new Vector<Method>(); 229 Method[] result; 230 for (Method method : allMethods) { 231 if (method.getName().equals(methodName)) { 232 matchedMethods.add(method); 233 } 234 } 235 result = new Method[matchedMethods.size()]; 236 for (int j = 0; j < matchedMethods.size(); ++j) { 237 result[j] = matchedMethods.elementAt(j); 238 } 239 return result; 240 } 241 242 void setReadMethod(Class<?> beanClass, String getterName) { 243 boolean result = false; 244 Method[] getters = findMethods(beanClass, getterName); 245 for (Method element : getters) { 246 try { 247 setReadMethod(element); 248 result = true; 249 } catch (IntrospectionException ie) { 250 } 251 if (result) { 252 break; 253 } 254 } 255 } 256 257 void setWriteMethod(Class<?> beanClass, String setterName) throws IntrospectionException { 258 boolean result = false; 259 Method[] setters = findMethods(beanClass, setterName); 260 for (Method element : setters) { 261 try { 262 setWriteMethod(element); 263 result = true; 264 } catch (IntrospectionException ie) { 265 } 266 if (result) { 267 break; 268 } 269 } 270 } 271 272 public PropertyEditor createPropertyEditor(Object bean) { 273 PropertyEditor editor; 274 if (propertyEditorClass == null) { 275 return null; 276 } 277 if (!PropertyEditor.class.isAssignableFrom(propertyEditorClass)) { 278 // beans.48=Property editor is not assignable from the 279 // PropertyEditor interface 280 throw new ClassCastException(Messages.getString("beans.48")); //$NON-NLS-1$ 281 } 282 try { 283 Constructor<?> constr; 284 try { 285 // try to look for the constructor with single Object argument 286 constr = propertyEditorClass.getConstructor(Object.class); 287 editor = (PropertyEditor) constr.newInstance(bean); 288 } catch (NoSuchMethodException e) { 289 // try no-argument constructor 290 constr = propertyEditorClass.getConstructor(); 291 editor = (PropertyEditor) constr.newInstance(); 292 } 293 } catch (Exception e) { 294 // beans.47=Unable to instantiate property editor 295 RuntimeException re = new RuntimeException(Messages.getString("beans.47"), e); //$NON-NLS-1$ 296 throw re; 297 } 298 return editor; 299 } 300} 301