It's Friday everybody!!!
You know what that means.
Two quickie things first.
1. I've been crazy busy w/firedrills this week. Stop. Drop. Roll. That's why we've been having radio silence on the blog front. Blog=Extracurricular.
2. Can somebody please explain to me why it is that all you Y-chromosome types have this propensity towards beeping at people. People you don't know. I walked to my parents house this week. (across the street). And going from here to there -- it can't be more than 100 meters -- somebody beeps at me. So I figure somebody's beeping at me, it must be somebody I know. Nope, just some yahoo in a pickup truck. What compels you to behave in this way? I have never in my entire life known a woman to randomly beep at people as she was driving down the street.
We digress...
We've got Friday Free Stuff to get to.
But first, some unfinished business...
Please find below the solution to last week's puzzler which came straight to my personal inbox directly CrazyBob (java.net, google fame... remember... he was our Sub last week). Please note, as he's a techno celeb I didn't have the courage to edit his language... don't be offended by it though... ..It's meant in an endearing way....
Last week's puzzle challenged you to
create an object o such that o.getClass().getMethods()
returned an inaccessible method. Michael Appleby posted the correct
solution first. He takes home the booty. Congratulations, you lucky
bastard.
The key to this puzzler: Class.getMethods()
returns all public methods regardless of the enclosing class's
scope. If we declare a public method in a package private (default
scope) class, the method is not actually accessible outside of the
package:
package bob;
class Bob {
public void inaccessible() {}
}
We can expose an instance of this class from a public class in the same package:
package bob;
public class BobFactory {
public static Object newBob() {
return new Bob();
}
}
Attempting to reflectively invoke the
method from another package throws an IllegalAccessException:
import bob.BobFactory;
public class PuzzlerSolution {
public static void main(String[] args) throws Exception {
Object o = BobFactory.newBob();
java.lang.reflect.Method[] methods =
o.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
if (methods[i].getName().equals("inaccessible"))
methods[i].invoke(o, null);
}
}
The output:
Exception in thread "main" java.lang.IllegalAccessException: Class PuzzlerSolution can not access a member of class bob.Bob with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:57)
at java.lang.reflect.Method.invoke(Method.java:317)
at PuzzlerSolution.main(PuzzlerSolution.java:10)
[Dis]honerable mentions:
- Andrew Taylor submitted the first attempt, but Andrew's code
actually throws
InvocationTargetException, notIllegalAccessException. - MooBob42 is incorrect. This is not currently considered a bug, though I agree it probably should be.
- Nic Laborera's solution throws an
IllegalArgumentException, but only because he passes in the wrong number of arguments. - Kris Schneider, a runner up, gets bonus points for reusing code from the core library to produce the smallest working solution. Nice work, Kris.
I first discovered this pitfall while testing code that traversed a graph of objects. To avoid a similar fate, minimize reflection. If there's a chance you could run into this exception, I advise silently logging it (a developer might have forgotten to make the class public).
(Have I ever mention that Free Stuff is the brand promise of MaryMaryQuiteContrary. And as I've personally participated in a branding workshop, I am an expert in these kinds of things.)
Everybody who posted wins a prize! Expectation set: a pen .(see picture below) It's a nice pen. But it's just a pen. Kris, you get two.
Claim your prize by sending me email with Friday Free Stuff in the subject line with your name and address. I will mail the pen to you with stamps I buy at the post office. (Michael, I'll send the fabulous prize package to you.). I won't share your personal info or use it for any other purpose whatsoever. I will delete the mail after I've copied it down. We got privacy policies around here, people.
My email address: mary.smaragdis-AT-sun.com.
Now let's get to this week's spectacular prize....

A pen. A really nice pen. (i got a lot of them. they fell off a truck.)
Submit a JavaOne session and tell me about it by posting a comment to this blog entry. Sessions that you've already submitted count. You don't have to think up a new one. First twenty people get a really nice pen.
Honor system. (Like I said, we got a privacy policy around here; I'd have no way of checking.)
You don't have to tell me what the session was about. I totally get how you want to keep it a secret until the call for papers closes on January 31.
All you gotta do to get a pen shipped directly to you -- entirely for free -- is submit a JavaOne session and be one of the first 20 people to tell me about it by posting a comment to this blog entry.
And in conclusion, I'd like to tell you all to go hug your number one.
Thanks for listening.
mary
Above is incorrect though...
package test; import java.lang.reflect.Method; public class O { class A { A() throws Exception { me(); //this is OK Class c = O.class; Method m = c.getDeclaredMethod("me", null); m.invoke(O.this, null); //this bombs out } } private void me() { System.out.println("me"); } public void o() throws Exception { A a = new A(); } public static void main(String[] args) throws Exception { O o = new O(); Method m[] = o.getClass().getMethods(); m[1].invoke(o, null); } }If you can call me() method in non-reflective way, and failed using reflection something is wrong. So most probably same thing is happening to most of solutions.
PS: Mary, I will pickup my consolation price though, to compensate my "hurt-geek-feelings". Can you make it two? also please...
:) - for humor impaired...
Posted by nic laborera on January 14, 2005 at 05:08 PM PST #
mary
Posted by mary on January 14, 2005 at 08:12 PM PST #
Posted by Bob Lee on January 16, 2005 at 02:23 PM PST #
It should invoke method o(), if it won't work for you. Try this:
public static void main(String[] args) throws Exception { O o = new O(); Method m[] = o.getClass().getMethods(); for (int i = 0; i < m.length; i++) { if ("o".equals(m[i].getName()) m[i].invoke(o, null); } }Thanks,
Nic
ps: above code is not tested, but I guess you get the idea.
Posted by Nic Laborera on January 17, 2005 at 09:24 PM PST #
Posted by Bob Lee on January 18, 2005 at 11:34 AM PST #
Posted by Nic Laborera on January 18, 2005 at 09:40 PM PST #