Search code examples
javajavabeans

Confusing behavior of java.beans.PropertyDescriptor(String, Class)


I'm trying to create a PropertyDescriptor for a bean class I have. I am calling

new PropertyDescriptor(myProperty, myClass)

and am seeing an exception that the method "isMyProperty" does not exist. Peeking into the code a bit --

/**
 * Constructs a PropertyDescriptor for a property that follows
 * the standard Java convention by having getFoo and setFoo
 * accessor methods.  Thus if the argument name is "fred", it will
 * assume that the writer method is "setFred" and the reader method
 * is "getFred" (or "isFred" for a boolean property).  Note that the
 * property name should start with a lower case character, which will
 * be capitalized in the method names.
 *
 * @param propertyName The programmatic name of the property.
 * @param beanClass The Class object for the target bean.  For
 *      example sun.beans.OurButton.class.
 * @exception IntrospectionException if an exception occurs during
 *              introspection.
 */
public PropertyDescriptor(String propertyName, Class<?> beanClass)
    throws IntrospectionException {
this(propertyName, beanClass, 
     "is" + capitalize(propertyName), 
     "set" + capitalize(propertyName));
}

The documentation says that it will look for "getFred" but it always uses "is" + capitalize(property)! This is in java version "1.6.0_31"

Thoughts?


Solution

  • Edit: I think I know what your problem is. If the property doesn't exist in your class, then you will get the "isProperty" method error. See my example:

        {
            PropertyDescriptor desc = new PropertyDescriptor("uuid", Company.class);
            Method m = desc.getReadMethod();
            System.out.println(m.getName()); /* prints getUuid */
        }
        {
            PropertyDescriptor desc = new PropertyDescriptor("uuid11", Company.class);
            Method m = desc.getReadMethod();
            System.out.println(m.getName()); /* throws Method not found: isUuid11 */
        }
    

    Original:

    It looks like it just defaults to isProperty as the read method, and if it doesn't exists, it uses getProperty. Take a look at the getReadMethod method, the bit where it goes:

    if (readMethod == null) {
        readMethodName = "get" + getBaseName();
    

    So it's trying the isProperty method first, and if it doesn't have that method, looks for getProperty.

    Here's the full method:

    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 = Introspector.findMethod(cls, readMethodName, 0);
        if (readMethod == null) {
            readMethodName = "get" + getBaseName();
            readMethod = Introspector.findMethod(cls, readMethodName, 0);
        }
        try {
            setReadMethod(readMethod);
        } catch (IntrospectionException ex) {
        // fall
        }
    }
    return readMethod;
    }