A Little Background
The package java.beans is part of Java Standard Edition since quite the beginning. Everybody has some understanding 
of what a JavaBean is. It is a convention which defines that java objects provide the following:
- a default constructor
 - getters and setters to access members
 - support for serialization
 
The main reason for this convention and the framework around it was to ease the instantiation and handling of GUI 
classes in AWT and swing. So most of you which have worked with a Java desktop GUI framework may know classes like 
PropertyChangeListener and PropertyEditor.
A very convenient part of the JavaBeans API is the introspection. It allows analyzing methods, parameters and properties of a Java class and provides merged information about these in so called descriptors.
The introspection is used in the roots of frameworks which need to analyze classes and instantiate them without actually knowing them. A few prominent examples are Spring and Stripes.
The Problem
A few weeks back I stumbled upon a weird and really hard to reproduce bug. The surface indication was that the frontend 
framework, which is Stripes, suddenly could not map some POST parameters to Java objects anymore. This bug only 
occurred on the test servers but never on local environments. After some intense remote debugging sessions I figured 
out that the cause was located in the 
java.beans.Introspector class utilized by 
Stripes to instantiate objects for request binding. For some reason the information returned by the introspector told 
Stripes that there are no setters for some properties.
The Cause
Recently generics have been added to a few classes used in request binding. Here is an simplified example of such a class:
public class User implements Identifiable<Integer> {
    
    private Integer id;
    
    public Integer getId() {
        return id;
    }
    
    public void setId(Integer id) {
        this.id = id;
    }
    
}The belonging interface:
public interface Identifiable<T> {
    T getId();
}The setter has been left out on the interface because the services interacting with Identifiables should not have the ability to set the id.
In Java generics are only known at compile time and are removed by the compiler through type erasure. This design decision has been made for the sake of backward compatibility, as most of the greatest flaws in software history.
The important thing to know is that the compiler will replace generic types by their bounds or Object (if unbounded), 
it will also insert type casts where necessary and will generate synthetic bridge methods to preserve polymorphism in 
extended generic types.
Knowing that, one can understand the output of the following:
for (Method method : User.class.getMethods()) {
    System.out.println(method);
}Output with Java Version 1.6.0_29:
public void User.setId(java.lang.Integer)
public java.lang.Integer User.getId()
public java.lang.Object User.getId()
//… the rest has been omitted for readability
The compiler added another method getId() to the User which has the return type Object. Though a programmer is 
forbidden to overload method return types the compiler can do that.
So the actual class now has two getters which return different types. The newly added getter is called a bridge method 
and will delegate every call to the Integer getter while casting the return type explicitly to Integer.
The actual root cause of the missing setter in the Stripes logic resides in the logic inside the 
java.beans.Introspector which could be simplified as:
- iterate over all methods and create PropertyDescriptors for each
 - iterate over all getter PropertyDescriptors
    
- remove redundant getter by merging them so that the last added getter for a property wins
 
 - iterate over all setter PropertyDescriptors and merge them into their appropriate getter PropertyDescriptors
 
Since the last getter method wins, the return type of this method will be made the type of the PropertyDescriptor and the logic may not find an appropriate setter because the types do not match. Tests with different Java versions showed different results in the order of methods and so different results of the following test:
@Test
public void test() throws Exception {
    final Class<User> clazz = User.class;
    final BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
    final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        
    for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            
        if (propertyDescriptor.getName().equals("id")) {              
            assertEquals(Integer.class, propertyDescriptor.getPropertyType());
            assertNotNull(propertyDescriptor.getReadMethod());
            assertNotNull(propertyDescriptor.getWriteMethod());
        }
    }
}Results for Java version 1.5.0_09:
assert: SUCCESS
assert: SUCCESS
assert: SUCCESS
Results for Java version 1.6.0_29:
assert: FAIL
assert: SUCCESS
assert: FAIL
Results for Java version 1.7.0:
assert: SUCCESS
assert: SUCCESS
assert: SUCCESS
Until Java version 1.7 there is no specific logic inside the Introspector which handles bridge methods. So the success of this test solely depends on the right order of methods, which only the compiler has the power of.
How to fix it
Upgrading to Java 1.7
If one has the freedom to do that, great! Despite the bug fixes Java 1.7 brings a lot of nice new features.
Wrap or Avoid Introspector
Usually upgrading to a new major Java versions is a thing which takes a while or may even be forbidden by company policies. It can also just not be possible because the software is a framework and needs to be run against different versions of Java (e.g. Spring).
So the solution is usually to not use the java.beans.Introspector at all or wrap around it to fix the problem.
Spring 
and Stripes and most certainly other projects 
do exactly that.
Avoid Asymmetry
When possible make getters and setters in classes and interfaces symmetrically. This will not fix the root cause that 
one might get a PropertyDescriptor for the wrong type e.g. Object instead of Integer, but at least one would have 
a setter and a getter.
This approach actually solved my problem, though Stripes is aware of the issue and tries to work around it, it does not cover all cases.
Conclusion
When using generics and java.beans.Introspector in Java versions below 1.7 be aware of unwanted side effects like 
missing setters or wrong types. In general beware of type erasure when working with generics especially in combination 
with reflection.
