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