JDK-4619536 : Introspector mixes property types in IndexedPropDesc's w/ inherited info
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.beans
  • Affected Version: 1.4.0,1.4.2,5.0
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS:
    generic,linux,solaris_2.6,windows_2000 generic,linux,solaris_2.6,windows_2000
  • CPU: generic,x86,sparc
  • Submitted: 2002-01-04
  • Updated: 2004-09-21
  • Resolved: 2004-09-21
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.
Other
5.0 b28Fixed
Related Reports
Duplicate :  
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Name: nt126004			Date: 01/04/2002


java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build
1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed
mode)


Full Operating System Version :

GLibC 2.1.3, kernel 2.2.12, RHL 6.1


A description of the problem :
Under some circumstances, it is possible for Introspector to
create an IndexedPropertyDescriptor which has inconsistent
types for the regular and indexed versions of the accessor.

Specifically: if a superclass provides an indexed property
with an indexed getter and a subclass provides a nonindexed
getter with the same name, an IndexedPropertyDescriptor will
be created by the default Introspector which has
inconsistent property types for PropDesc.getPropType vs.
IdxdPropDesc.getIdxdPropType.

Originally observed in NetBeans IDE. A class extending
JPanel had a method public Component getComponent (to
implement some random interface). Selecting the source and
choosing Customize Bean, which is supposed to open a
property sheet permitting its properties to be edited and an
instance serialized, threw an exception: reported as #17728
on www.netbeans.org and worked around (see below). The
problem was that Container.getComponent(int) and Component
org.netbeans.core.ui.IDESettingsPanel.getComponent() were
mashed into the same (indexed) prop desc; the property sheet
code in NetBeans saw an IndexedPropertyDescriptor with a
getPropertyType, assumed it would be an array type according
to the JavaBeans spec, and tried to use it an array, and
failed.

Including simpler test case showing that the two types need
not be related. Here Date B.foo is unrelated to the indexed
int A.foo[]. It is a bug in Introspector to put them both in
the same property. Since a bean can have only one property
with a given name, it ought to hide int A.foo[] and return a
plain PropertyDescriptor, type Date, name foo, getter public
Date B.foo(), no setter.

#4477877 reported a number of problems with Introspector,
but these had to do with unreproducible load order. This is
different, it is reproducible as far as I know. #4168833 is
very similar, but not identical, to this bug.

Occurs in both 1.3.1_01 and 1.4 beta 3.

Steps to follow to reproduce the problem :
1. Compile and run the included test class.

Expected versus actual behavoir :
Actual results:

---%<---
prop: class<class java.lang.Class>
	public final native java.lang.Class
java.lang.Object.getClass()
	null
indexed prop: foo<class java.lang.String>
	public java.lang.String Test17728$A.getFoo(int)
	null
regular prop info also:
prop: foo<class java.util.Date>
	public java.util.Date Test17728$B.getFoo()
	null
---%<---

Expected results:

---%<---
prop: class<class java.lang.Class>
	public final native java.lang.Class
java.lang.Object.getClass()
	null
prop: foo<class java.util.Date>
	public java.util.Date Test17728$B.getFoo()
	null
---%<---


This bug can be reproduced always.

---------- Begin Source ----------
import java.beans.*;
import java.util.Date;
public class Test17728 {
    public static void main (String args[]) throws Exception
{
        BeanInfo y = Introspector.getBeanInfo(B.class);
        PropertyDescriptor[] p = y.getPropertyDescriptors();
        for (int i = 0; i < p.length; i++) {
            if (p[i] instanceof IndexedPropertyDescriptor) {
                IndexedPropertyDescriptor ipe =(IndexedPropertyDescriptor)p[i];
                System.out.println("indexed prop: " +ipe.getName() + "<" + ipe.getIndexedPropertyType() + ">");
                System.out.println("\t" +ipe.getIndexedReadMethod() + "\n\t" +ipe.getIndexedWriteMethod());
                System.out.println("regular prop info also:");
            }
            System.out.println("prop: " + p[i].getName() +"<" + p[i].getPropertyType() + ">");
            System.out.println("\t" + p[i].getReadMethod() +"\n\t" +p[i].getWriteMethod());
        }
    }
    public static class A {
        public String getFoo(int x) {return null;}
    }
    public static class B extends A {
        public Date getFoo() {return null;}
    }
}

---------- End Source ----------

  Customer Workaround :
Work around (used in NetBeans' org.openide.nodes.BeanNode):
after getting PropertyDescriptor's from
Introspector.getBeanInfo, clean them up: if there are any
IndexedPropertyDescriptor's where getPropertyType() is not
null and yet not an array type, throw them out (ignore those
properties). Does not let the subclass property be used, but
at least prevents class cast exceptions and so on.
(Review ID: 137384) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger tiger-beta FIXED IN: tiger-beta INTEGRATED IN: tiger-b28 tiger-beta VERIFIED IN: 1.5.0_01
22-09-2004

EVALUATION IndexedPropertyDescriptor extends PropertyDescriptor but they don't really share methods and properties. The ideal IndexedProperty would have the following methods // Indexed PD public void setFoo(int, FooType); public FooType getFoo(int); // Basic PD public FooType getFoo(); public void setFoo(FooType[]); The base PropertyDescriptor would have: type: FooType[] read: FooType[] getFoo(); write: setFoo(FooType[]) When cast to an IndexedPropertyDescriptor, the new values of the IPD should be: indexed type: FooType indexed read: FooType getFoo(int); indexed write: setFoo(int, FooType) The challenge is to make the algorithm intelligent to detect the ambiguous situations in which these method types span a class hierachy and may change types. For example, the JComponent inpuMap property looks like an indexed type but defines a "convenience" method which breaks JavaBeans: void setInputMap(int, InputMap) InputMap getInputMap(int) The convenience method will get the WHEN_FOCUSED inputmap. InputMap getInputMap(); In order to be Bean compliant, this should return an array of InputMap. Type changes are even more ambiguous. In the following situation, the type of the rec property is ambiguous. Is the desirable type a String or a TestBean? public class TestBeanParent { public void setRec(String rec) { } public TestBean getRec(int index) { return null; } } public class TestBean extends TestBeanParent { public TestBean getRec() { return null; } } Likewise, the following situation shows the ambiguity of the foo type: public static class A { public String getFoo(int x) {return null;} } public static class B extends A { public Date getFoo() {return null;} } The best way to resolve ambiguous types is for the developer to write a BeanInfo meta data class which will make the desirable type explicit. The existence of a BeanInfo class will be used rather than relying on the the Introspector to resolve these using reflection. Another possible solution for the descriptors to cancel out the changing types. Perhaps the findPropetyType() and findIndexedPropertyType() methods shouldn't throw exceptions when it detects that the type has changed. Instead, a decision should be made to resolve the ambiguity perhaps by making the inhierited class take precedence. ###@###.### 2003-03-17 The IndexedPropertyDescriptor should not have contradictory types between the indexedPropertyType and the normal PropertyType. The Introspecton algorithm has been tweaked to exclude property descriptors in which the type doesn't match. ###@###.### 2003-10-15
15-10-2003