/** * This constructor takes the name of a simple property, and Method objects for reading and * writing the property. * * @param propertyName The programmatic name of the property. * @param readMethod The method used for reading the property value. May be null if the property * is write-only. * @param writeMethod The method used for writing the property value. May be null if the property * is read-only. * @exception IntrospectionException if an exception occurs during introspection. */ public PropertyDescriptor(String propertyName, Method readMethod, Method writeMethod) throws IntrospectionException { if (propertyName == null || propertyName.length() == 0) { throw new IntrospectionException("bad property name"); } setName(propertyName); setReadMethod(readMethod); setWriteMethod(writeMethod); }
/** * Gets the method that should be used to read the property value. * * @return The method that should be used to read the property value. May return null if the * property can't be read. */ public synchronized Method getReadMethod() { Method readMethod = getReadMethod0(); if (readMethod == null) { Class cls = getClass0(); if (cls == null || (readMethodName == null && readMethodRef == null)) { // The read method was explicitly set to null. return null; } if (readMethodName == null) { Class type = getPropertyType0(); if (type == boolean.class || type == null) { readMethodName = "is" + getBaseName(); } else { readMethodName = "get" + getBaseName(); } } // Since there can be multiple write methods but only one getter // method, find the getter method first so that you know what the // property type is. For booleans, there can be "is" and "get" // methods. If an "is" method exists, this is the official // reader method so look for this one first. readMethod = MethodUtils.findAccessibleMethodIncludeInterfaces(cls, readMethodName, 0, null); if (readMethod == null) { readMethodName = "get" + getBaseName(); readMethod = MethodUtils.findAccessibleMethodIncludeInterfaces(cls, readMethodName, 0, null); } try { setReadMethod(readMethod); } catch (IntrospectionException ex) { // fall } } return readMethod; }
/** * Package-private constructor. Merge two property descriptors. Where they conflict, give the * second argument (y) priority over the first argument (x). * * @param x The first (lower priority) PropertyDescriptor * @param y The second (higher priority) PropertyDescriptor */ PropertyDescriptor(PropertyDescriptor x, PropertyDescriptor y) { super(x, y); if (y.baseName != null) { baseName = y.baseName; } else { baseName = x.baseName; } if (y.readMethodName != null) { readMethodName = y.readMethodName; } else { readMethodName = x.readMethodName; } if (y.writeMethodName != null) { writeMethodName = y.writeMethodName; } else { writeMethodName = x.writeMethodName; } if (y.propertyTypeRef != null) { propertyTypeRef = y.propertyTypeRef; } else { propertyTypeRef = x.propertyTypeRef; } // Figure out the merged read method. Method xr = x.getReadMethod(); Method yr = y.getReadMethod(); // Normally give priority to y's readMethod. try { if (yr != null && yr.getDeclaringClass() == getClass0()) { setReadMethod(yr); } else { setReadMethod(xr); } } catch (IntrospectionException ex) { // fall through } // However, if both x and y reference read methods in the same class, // give priority to a boolean "is" method over a boolean "get" method. if (xr != null && yr != null && xr.getDeclaringClass() == yr.getDeclaringClass() && xr.getReturnType() == boolean.class && yr.getReturnType() == boolean.class && xr.getName().indexOf("is") == 0 && yr.getName().indexOf("get") == 0) { try { setReadMethod(xr); } catch (IntrospectionException ex) { // fall through } } Method xw = x.getWriteMethod(); Method yw = y.getWriteMethod(); try { if (yw != null && yw.getDeclaringClass() == getClass0()) { setWriteMethod(yw); } else { setWriteMethod(xw); } } catch (IntrospectionException ex) { // Fall through } if (y.getPropertyEditorClass() != null) { setPropertyEditorClass(y.getPropertyEditorClass()); } else { setPropertyEditorClass(x.getPropertyEditorClass()); } bound = x.bound | y.bound; constrained = x.constrained | y.constrained; }