United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4918902 REGRESSION 1.4: PropertyDescriptors do not find the most specific methods
JDK-4918902 : REGRESSION 1.4: PropertyDescriptors do not find the most specific methods

Details
Type:
Bug
Submit Date:
2003-09-08
Status:
Closed
Updated Date:
2004-07-22
Project Name:
JDK
Resolved Date:
2003-11-03
Component:
client-libs
OS:
solaris_7
Sub-Component:
java.beans
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.3.1_08
Fixed Versions:
1.3.1_11 (11)

Related Reports
Backport:
Backport:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description

Name: dk106046			Date: 09/08/2003

Operating System:
Solaris 2.8
                                                  
Full JDK version:
1.3.1_08
                             
Problem details:
After upgrading from 1.3.1_04 to 1.3.1_08, an application using struts
introspection fails with the following error:
Servlet Error: No getter method for property dn of bean calist:                           
javax.servlet.jsp.JspException: No getter method for property dn of bean calist                                                                  
  at org.apache.struts.util.RequestUtils.lookup(RequestUtils.java:742) 

Many apps in the system use struts introspection, but it is only this app in
particular that fails under 1.3.1_08. One of its JSPs makes a struts call
to  <bean:write name="calist" property="dn"/>. It is just this ONE dn property
that causes the problem, which manifests itself as the servlet error above.
Reverting back to 1.3.1_04 fixes the problem, but 1.3.1_08 is required for other
bug fixes and so downgrading is not an acceptable workaround for long.              
.                                                                       
JDK 1.3.1_08 introduced a fix for sunbug 4477877. The customer strongly suspects
that this  fix is the cause of their new problem 1.3.1_08.                       
.                                                                       
Struts clearly uses introspection to find the getter methods for the bean
properties, and with the _08 level, is apparently unable to find the getter method
for the dn property (i.e. getDn()). Note that we know about the lowercase vs.
uppercase issue that seems to catch a lot of struts users.  This is NOT that
problem.  We re using it properly, and it DID work before this JDK upgrade.                                                                                                       
Our getDn() method DOES exist in a class file that is in the classpath. 
The interesting/unique thing about getDn() is that it calls a superclass
getDn().                                                                                                   

Source code and flow analysis is available on request.

======================================================================

                                    

Comments
WORK AROUND



Name: dk106046			Date: 09/08/2003

Downgrade to 1.3.1_07.
======================================================================


The fix was made in the Intropector so you could take the Introspector classes from a previous version and prepend the bootclasspath:

-Xbootclasspath/p:<path to patched classes>


###@###.### 2003-09-16
                                     
2003-09-16
SUGGESTED FIX

The package private constructor for PropertyDescriptor that merges two property descriptors should be smarter about merging methods.

Read and Write methods in the second property descriptor should not be the methods used if they represent methods from a superclass. The methods used should be from the closest from the class hierarchy.

There is also another problem related to the Soft/Weak reference work in 4809008: setRead/WriteMethod should *always* call setRead/WriteClass0() 		with the getDeclaredClass() other wise it could produce the wrong method after SoftReference collection. 

----

The setRead/WriteClass0() was removed in both PD and IPD since those cases may be covered in a get/setClass0() that will hold the most specific class. The read and write methods can be found in the hierarchy using the Introspector.findMethod.

The solution is a combination of these diffs:
http://sa.sfbay.sun.com/projects/swing_data/tiger/4918902.2/
http://sa.sfbay.sun.com/projects/swing_data/tiger/4918902.3/

###@###.### 2003-10-22
                                     
2003-10-22
EVALUATION

There is no doubt that the Introspection mechanism has changed due to the backported bug. The changes to the Introspector were significant. 

It's difficult to diagonse the problem and suggest a workaround without seeing the API for the contentious class. The resolution of 4477877 concerned the role of determining the getter and setters for a property taking into accound of the existence of simple getter and setter methods, methods split across a class hierarchy, and the existence of index getter and setter methods.


Uploaded requested data from Customer (reflectionproblem.zip)

###@###.### 2003-09-17

The essence of the problem is that the Introspector is not using getting the subclassed getDn() method as the reader method and is using the superclass getDn() method. This changed from 1.3.1_07 - > 1.3.1_08. These changes were originally done in 1.4 and were backported to 1.3.1_08. Note that a subclasses setter method will correctly be retrieved.

I think struts is expecting the subclasses getter method - which is different from the getter method returned from Introspection.

Here is a simplified test case which shows the essence of this problem:

----- Test.java ----------------------------------------------------------
import java.beans.*;

import java.lang.reflect.Method;

public class Test {

    public static void main(String[] args) throws Exception {
	print(Bean1.class);
	print(Bean2.class);
    }

    public static void print(Class clz) throws IntrospectionException {
	System.out.println(clz.getName());

	BeanInfo bi = Introspector.getBeanInfo(clz);

	PropertyDescriptor[] props = bi.getPropertyDescriptors();
	for (int i = 0; i < props.length; i++) {
	    Class type = props[i].getPropertyType();
	    String name = props[i].getName();
	    Method read = props[i].getReadMethod();
	    Method write = props[i].getWriteMethod();
	    
	    if ("foo".equals(name)) {
		System.out.println("Property: " + name + " type: " + type);
		System.out.println("\twrite: " + write);
		System.out.println("\tread: " + read);

		// getFoo method is defined on both classes so the class declared method
		// should be used as the most specific method.
		if (read.getDeclaringClass() != clz) {
		    throw new RuntimeException(read.getDeclaringClass() + " for " + 
					       read.getName() + " != " + clz);
		}
	    }
	}
    }

    public static class Bean1 {
	
	private String foo;

	public String getFoo() {
	    return foo;
	}

	public void setFoo(String foo) {
	    this.foo = foo;
	}
    }

    public static class Bean2 extends Bean1 {
	
	// Overriddent getFoo method should be selected as the 
	// reader method for the property.
	public String getFoo() {
	    return super.getFoo();
	}
    }
}
----------- Test.java

A correct execution:
[davidson@azonic reflection problem]$ /java/re/jdk/1.3.1_07/archive/fcs/binaries/linux-i586/bin/java Test
Test$Bean1
Property: foo type: class java.lang.String
        write: public void Test$Bean1.setFoo(java.lang.String)
        read: public java.lang.String Test$Bean1.getFoo()
Test$Bean2
Property: foo type: class java.lang.String
        write: public void Test$Bean1.setFoo(java.lang.String)
        read: public java.lang.String Test$Bean2.getFoo()


Test execution in 1.3.1_08, 1.4, 1.4.1, 1.4.2, 1.5-beta:

[davidson@azonic reflection problem]$ /java/re/jdk/1.3.1_08/archive/fcs/binaries/linux-i586/bin/java Test
Test$Bean1
Property: foo type: class java.lang.String
        write: public void Test$Bean1.setFoo(java.lang.String)
        read: public java.lang.String Test$Bean1.getFoo()
Test$Bean2
Property: foo type: class java.lang.String
        write: public void Test$Bean1.setFoo(java.lang.String)
        read: public java.lang.String Test$Bean1.getFoo()
Exception in thread "main" java.lang.RuntimeException: class Test$Bean1 for getFoo != class Test$Bean2
        at Test.print(Test.java:32)
        at Test.main(Test.java:9)

                                     
2004-07-23
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.3.1_11
1.4.2_06
generic
tiger
tiger-beta

FIXED IN:
1.3.1_11
1.4.2_06
tiger-beta

INTEGRATED IN:
1.3.1_11
1.4.2_06
tiger-b28
tiger-beta

VERIFIED IN:
1.3.1_11
1.4.2_06


                                     
2004-07-23



Hardware and Software, Engineered to Work Together