JDK-4918902 : REGRESSION 1.4: PropertyDescriptors do not find the most specific methods
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 1.3.1_08
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_7
  • CPU: x86
  • Submitted: 2003-09-08
  • Updated: 2004-07-22
  • Resolved: 2003-11-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
1.3.1_11 11Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  

Name: dk106046			Date: 09/08/2003

Operating System:
Solaris 2.8
Full JDK version:
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

Source code and flow analysis is available on request.


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

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)

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

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