Hey All,

I've been working on a bug fix for STS-330, which describes a bug  
whereby the property binding code doesn't like working with  
Map.Entry's (and more generally, public properties specified in  
public interfaces, and implemented in private classes).

I've tracked down what I believe is the cause of the problem, and  
have a nice little test case and solution - but since this looks to  
me like a bug in Sun's Java implementation, I'd really like to get  
some other opinions on it before I a) work around it and b) post it  
to the bug parade.

Essentially what's happening is as follows.  When introspecting a  
class which is private, but is an implementation of a public  
interface, the Introspector returns PropertyDescriptors which contain  
references to the methods in the private class instead of those in  
the public interface. The JLS (section 6.6.1) defines an object as  
accessible (assuming it's in a different package) only if the object  
is public and the type containing it is public - which in this case  
it's not.  So when you invoke the read or write methods, you get  
access exceptions :(  This seems to be a bug in the Introspector if  
you ask me.

The second bizarro thing I discovered is that calling isAccessible()  
on public methods of public interfaces seems to return false!  So  
you'll see in the example code below that I actually check the  
interface and member for the public modifier, because isAccessible()  
returns false.  I can't find anything either way on this in the JLS,  
but given the prior statement (if the member is public and the type  
is public) and no contrary statements about requiring concrete types,  
this seems like a bug also!

Anyway, if someone could take a few minutes to read through the test  
case below, and see if you can find some holes in my logic, I'd  
appreciate it.

-t

-------------------------------------------------------

package net.sourceforge.stripes.test;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import static java.lang.reflect.Modifier.isPublic;
import java.util.HashMap;
import java.util.Map;

public class PrivateInnerTest {
     public static void main(String[] args) throws Exception {
         Map<String,String> map = new HashMap<String,String>();
         map.put("foo", "bar");
         Map.Entry<String,String> entry = map.entrySet().iterator 
().next();

         BeanInfo info = Introspector.getBeanInfo(entry.getClass());
         for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
             Method m1 = pd.getReadMethod();
             Method m2 = resolveAccessibleMethod(m1);

             //Works
             System.out.println(pd.getName() + ": " + m2.invoke(entry));

             // Explodes sometimes
             System.out.println(pd.getName() + ": " + m1.invoke(entry));
         }
     }

     public static final Method resolveAccessibleMethod(Method m)  
throws Exception {
         // If the passed in method is accessible, then just give it  
back.
         if (m.isAccessible()) return m;

         final Class<?> clazz    = m.getDeclaringClass();
         final String name    = m.getName();
         final Class<?>[] ptypes = m.getParameterTypes();

         // Else, loop through the interfaces for the declaring  
class, looking for a
         // public version of the method that we can call
         for (Class<?> iface : clazz.getInterfaces()) {
             try {
                 Method m2 = iface.getMethod(name, ptypes);
                 if (m2.isAccessible()) return m2;
                 if (isPublic(iface.getModifiers()) && isPublic 
(m2.getModifiers())) return m2;
             }
             catch (NoSuchMethodException nsme) { /* Not Unexpected.  
*/ }
         }

         // Else loop through the superclasses looking for a public  
method
         Class<?> c = clazz.getSuperclass();
         while (c != null) {
             try {
                 Method m2 = c.getMethod(name, ptypes);
                 if (m2.isAccessible()) return m2;
                 if (isPublic(c.getModifiers()) && isPublic 
(m2.getModifiers())) return m2;
             }
             catch (NoSuchMethodException nsme) { /* Not Unexpected.  
*/ }

             c = c.getSuperclass();
         }

         // If we haven't found anything at this point, just give up!
         return m;
     }
}



-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Stripes-development mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/stripes-development

Reply via email to