Explicitly and without apology a marketing vehicle MaryMaryQuiteContrary

Friday Jan 14, 2005



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, not IllegalAccessException.
  • 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).


Which would make Michael Appleby our winner!!!!

(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....

nice ink pen

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

Comments:

Nic Laborera's solution throws an IllegalArgumentException, but only because he passes in the wrong number of arguments.

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 #

you got it, Nic! Two pens for you. I'll throw in a mouse pad too. (remind me when you send me email w/your address.)

mary

Posted by mary on January 14, 2005 at 08:12 PM PST #

Nic, I'm not sure I understand. Can you please elaborate? You can't determine the result of the program above becuase there are no guarantees on the ordering of the methods. When I ran it, I think I must have gotten "equals(Object)" as the first method. What method did you intend to invoke? I'll try it again when I get home.

Posted by Bob Lee on January 16, 2005 at 02:23 PM PST #

Hi Bob,
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 #

Ahhh, that throws InvocationTargetException.

Posted by Bob Lee on January 18, 2005 at 11:34 AM PST #

And because of?

Posted by Nic Laborera on January 18, 2005 at 09:40 PM PST #

Post a Comment:
Comments are closed for this entry.