-
Bug
-
Resolution: Fixed
-
P3
-
6
-
b102
-
x86
-
windows_xp
FULL PRODUCT VERSION :
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
Unlike Method.getDeclaredMethod, Introspector.internalFindMethod returns the first method with a name and parameter match, but this is not necessarily the most specific method. Instead of short circuiting as soon as a match is found, all public declared methods should be checked and the most specific method match should be returned.
This only occurs when I have "bridge" methods on my class (e.g., two methods with the same signature, but different return types).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
This bug cannot be reliably reproduced because according to the documentation, the ordering of the methods is not guaranteed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I was expecting that I would always get the "most specific" method, but I actually get a randomly chosen Method (whichever happened to be returned first by the JVM).
ACTUAL -
Under certain conditions which are difficult to reproduce, the ordering of methods returned by the JVM is different for getDeclaredMethods, and as a result, Introspector.internalFindMethod will return a different result.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
public class TestCase {
public static final void main(String[] args) throws Exception {
for (Method method : Foobar.class.getDeclaredMethods()) {
System.out.println(method);
}
System.out.println();
for (PropertyDescriptor pd : Introspector.getBeanInfo(Foobar.class).getPropertyDescriptors()) {
System.out.println("Property: " + pd.getName());
System.out.println("Read Method: " +pd.getReadMethod());
System.out.println("Write Method: " + pd.getWriteMethod());
System.out.println();
}
}
public interface Foo {
Collection<Bar> getBars();
void setBars(Iterable<Bar> bars);
}
public class Bar {
}
public class Foobar implements Foo {
Set<Bar> bars;
public Set<Bar> getBars() {
return this.bars;
}
public void setBars(Iterable<Bar> bars) {
Set<Bar> set = new LinkedHashSet<Bar>();
for (Bar bar : bars) {
set.add(bar);
}
this.bars = set;
}
}
}
/* Sample output:
public java.util.Set TestCase$Foobar.getBars()
public java.util.Collection TestCase$Foobar.getBars()
public void TestCase$Foobar.setBars(java.lang.Iterable)
public void TestCase$Foobar.setBars(java.util.Set)
Property: bars
Read Method: public java.util.Collection TestCase$Foobar.getBars()
Write Method: null
Property: class
Read Method: public final native java.lang.Class java.lang.Object.getClass()
Write Method: null
*/
/* In my opinion, the proper result should have been:
public java.util.Set TestCase$Foobar.getBars()
public java.util.Collection TestCase$Foobar.getBars()
public void TestCase$Foobar.setBars(java.lang.Iterable)
public void TestCase$Foobar.setBars(java.util.Set)
Property: bars
Read Method: java.util.Set TestCase$Foobar.getBars()
Write Method: TestCase$Foobar.setBars(java.util.Set)
Property: class
Read Method: public final native java.lang.Class java.lang.Object.getClass()
Write Method: null
*/
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I can create a BeanInfo class for my Java Bean to return the correct method, but I have to use the PropertyDescriptor constructor that takes Method parameters and not the variant which takes the method names as Strings, else PropertyDescriptor will call Introspector.findMethod (which in turn calls internalFindMethod) which demonstrates the problem described above.
java version "1.6.0_01"
Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows XP [Version 5.1.2600]
A DESCRIPTION OF THE PROBLEM :
Unlike Method.getDeclaredMethod, Introspector.internalFindMethod returns the first method with a name and parameter match, but this is not necessarily the most specific method. Instead of short circuiting as soon as a match is found, all public declared methods should be checked and the most specific method match should be returned.
This only occurs when I have "bridge" methods on my class (e.g., two methods with the same signature, but different return types).
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
This bug cannot be reliably reproduced because according to the documentation, the ordering of the methods is not guaranteed.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I was expecting that I would always get the "most specific" method, but I actually get a randomly chosen Method (whichever happened to be returned first by the JVM).
ACTUAL -
Under certain conditions which are difficult to reproduce, the ordering of methods returned by the JVM is different for getDeclaredMethods, and as a result, Introspector.internalFindMethod will return a different result.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
public class TestCase {
public static final void main(String[] args) throws Exception {
for (Method method : Foobar.class.getDeclaredMethods()) {
System.out.println(method);
}
System.out.println();
for (PropertyDescriptor pd : Introspector.getBeanInfo(Foobar.class).getPropertyDescriptors()) {
System.out.println("Property: " + pd.getName());
System.out.println("Read Method: " +pd.getReadMethod());
System.out.println("Write Method: " + pd.getWriteMethod());
System.out.println();
}
}
public interface Foo {
Collection<Bar> getBars();
void setBars(Iterable<Bar> bars);
}
public class Bar {
}
public class Foobar implements Foo {
Set<Bar> bars;
public Set<Bar> getBars() {
return this.bars;
}
public void setBars(Iterable<Bar> bars) {
Set<Bar> set = new LinkedHashSet<Bar>();
for (Bar bar : bars) {
set.add(bar);
}
this.bars = set;
}
}
}
/* Sample output:
public java.util.Set TestCase$Foobar.getBars()
public java.util.Collection TestCase$Foobar.getBars()
public void TestCase$Foobar.setBars(java.lang.Iterable)
public void TestCase$Foobar.setBars(java.util.Set)
Property: bars
Read Method: public java.util.Collection TestCase$Foobar.getBars()
Write Method: null
Property: class
Read Method: public final native java.lang.Class java.lang.Object.getClass()
Write Method: null
*/
/* In my opinion, the proper result should have been:
public java.util.Set TestCase$Foobar.getBars()
public java.util.Collection TestCase$Foobar.getBars()
public void TestCase$Foobar.setBars(java.lang.Iterable)
public void TestCase$Foobar.setBars(java.util.Set)
Property: bars
Read Method: java.util.Set TestCase$Foobar.getBars()
Write Method: TestCase$Foobar.setBars(java.util.Set)
Property: class
Read Method: public final native java.lang.Class java.lang.Object.getClass()
Write Method: null
*/
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
I can create a BeanInfo class for my Java Bean to return the correct method, but I have to use the PropertyDescriptor constructor that takes Method parameters and not the variant which takes the method names as Strings, else PropertyDescriptor will call Introspector.findMethod (which in turn calls internalFindMethod) which demonstrates the problem described above.
- relates to
-
JDK-6976577 JCK7 api/java_beans/EventSetDescriptor/descriptions.html#Ctor1 fails since jdk7 b102
-
- Resolved
-