aspose file tools*
The moose likes Java in General and the fly likes Accessing Outer Class Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Accessing Outer Class" Watch "Accessing Outer Class" New topic
Author

Accessing Outer Class

Paul Keohan
Ranch Hand

Joined: Mar 15, 2000
Posts: 411
I am getting an instance of an object which turns out to be an anonymous inner class. Is there a way to access the corresponding outer class object in this situation? By 'access' I mean, can I run methods on the outer object just by having the inner class object instance.

Thanks.
Paul
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1871
hi Paul,
as of my knowledge 'you cannot do it easily'.
here are solutions i think should work for u,
1.
in case you had the control over the source, u can provide delegating methods in the inner class that calls the outer class methods
2.
u can use reflection api to get a outer class name and then use reflection api to get methods and execute them..
look at getDeclaringClass() method of the java.lang.Class and see if that helps...
3.
u can keep an explicit reference to the outer class in the inner class and then access that reference to invoke methods of the outerclass..
e.g. something like...
class outer {
outer o = this;
class inner {
outer o1 = o;
}
}
now use o1 of inner class to access method of the outer class...
hope this helps and i understood your question correctly..
regards
maulin.
Paul Keohan
Ranch Hand

Joined: Mar 15, 2000
Posts: 411
Thanks for your help Maulin.
I'll give that class method a try. The problem is I don't have access to the source code. I can see it using a decompiler but I can't change any of it. The inner class is a JComponent type object. The outer class isn't, so the method I want to run from the outer class can't be run by casting the inner class into a JComponent.
Paul
Michael Morris
Ranch Hand

Joined: Jan 30, 2002
Posts: 3451

2.
u can use reflection api to get a outer class name and then use reflection api to get methods and execute them..

I don't think so from an anonymous inner class. You can get to the enclosing class metadata but you can't get that particular instance of the class. The VM has no notion of inner classes. That's all done with the compiler. The compiler does assign a reference to the instance of the enclosing class and names it this$0 and declares it private final. If you try to set the accessibility of it you will get a RuntimeException.
Look at this :

Here is the output:

I am by no means an expert in Reflection, but I think you're kicking a dead dog if you expect to get to the enclosing class instance thru an anonymous inner class. Maybe some of the other gurus here can set me right if I'm wrong here. It would be a nice trick.
Michael Morris


Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius - and a lot of courage - to move in the opposite direction. - Ernst F. Schumacher
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1871
hi Michael,
i meant following,

the output is,
inner.display()
outer.printIt():Hello

regards
maulin.
Michael Morris
Ranch Hand

Joined: Jan 30, 2002
Posts: 3451
Hi Maulin,

Originally posted by Paul Keohan:
I am getting an instance of an object which turns out to be an anonymous inner class. Is there a way to access the corresponding outer class object in this situation?

Your code creates a new instance of the enclosing class and your inner class is named. Try calling getDeclaringClass() on an instance of an anonymous inner class and see what happens.
Michael Morris
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
Michael - in fact it is possible to access the outer instance. Note that the exception was IllegalArgumentException, and it's thrown from fields[i].get(name), not from the setAccess() method. The problem is that
Object outer = fields[i].get(name);
should be
Object outer = fields[i].get(in);
The argument to Field's get() method must be the particular instance of the class whose field value you want to access - i.e., instance of the inner class in this case.
A few more things worth noting:
Depending on your security manager's settings, you may not have the required access to execute the setAccessible method. E.g. the default settings for an Applet won't let you do this, I think. So code should probably be prepared for the possibility that access is not allowed.
Also, there's no guarantee that the field we want will always be called this$0. Some classes may have other private anonymous fields for other reason, and so the field may be "this$1" or something else. The only specs I can find for this are indicated here in the JVM spec; by following the link and waiting for a really lengthy download, you get the old Inner Classes Specification which contains the following:
Class name transformations
Names of nested classes are transformed as necessary by the compiler to avoid conflicts with identical names in other scopes. Names are encoded to the virtual machine by taking their source form, qualified with dots, and changing each dot `.' after a class name into a dollar sign `$'. (Mechanical translators are allowed to use dollar signs in Java.)
When a class name is private or local to a block, it is globally inaccessible. A compiler may opt to code such an inaccessible name by using an accessible enclosing class name as a prefix, followed by a `$' separator and a locally unique decimal number. Anonymous classes must be encoded this way.
So, an inner class pkg.Foo.Bar gets a run-time name of pkg.Foo$Bar, or perhaps something like pkg.Foo$23, if Bar is a private member or local class. Implementations must conform to the format of names, even globally inaccessible ones, so that debuggers and similar tools can recognize them.
Any class file which defines or uses a transformed name also contains an attribute (as supported by the 1.0 file format) recording the transformation. These attributes are ignorable by the virtual machine and by 1.0 compilers. The format of this attribute is described in the section on binary compatibility.

For our purposes, it's probably best to minimize assumptions about the field name. I'd probably loop through all fields and look for one whose type matched that of the outer class. If there's only one such field, that's it; otherwise, ummm, I dunno. Again, the program should probably be prepared for the possibility that the field cannot be determined with certainty.


"I'm not back." - Bill Harding, Twister
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1871
hi Michale,
i now understand what u meant and what was asked in the original question. yeah....u were right..
btw, i knew that whenever we create a "annonymous inner" class we actually "extend" the definition of the class...and so i came up with another workaround...
first, i tried that getDeclaringClass() as you suggested and i got "NullPointerException" you know...but as that Extend logic goes indicated in my previous line, u can do,

it works!!!
we can make sure that extend thing like this,
1. replace the setInner() method like this,

2. add a method mymethod() in the definition of the abstract class Inner like this,

3. put in.mymethod() in the main() method after we get Inner in = (Inner)it.getInner();
the output for the call to in.mymethod() would be - "overridden mymethod" !

regards
maulin
Michael Morris
Ranch Hand

Joined: Jan 30, 2002
Posts: 3451

Originally posted by Jim Yingst
Note that the exception was IllegalArgumentException, and it's thrown from fields[i].get(name), not from the setAccess() method. The problem is that
Object outer = fields[i].get(name);
should be
Object outer = fields[i].get(in);

DOH! I actually knew that. And with that change it does work. You can call:

As you can see, I haven't worked too much with Reflection. Just haven't found a practical need for it in my real world apps.

Originally posted by Maulin Vasavada
... it works!!!

I'll take a look at your code but as Jim pointed out I had a dumb mistake in my code that caused the Exception and with that one change, we can now access the outer class instance. But as Jim also points out, my solution is not 100% deterministic since it depends on compiler semantics and the whim of whatever SecurityManager is in place.
Michael Morris
Paul Keohan
Ranch Hand

Joined: Mar 15, 2000
Posts: 411
Thanks everyone. I managed to do what I needed to do entirely because of your help. Here's the code I used to run the method that I wanted to get to.
Michael Morris
Ranch Hand

Joined: Jan 30, 2002
Posts: 3451
Hi Paul,
You need to take a close look at Jim's post. The use of this$0 is not guaranteed to work.
Michael Morris
Paul Keohan
Ranch Hand

Joined: Mar 15, 2000
Posts: 411
I'll check that out and make it more generic.
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1871
hi Paul,
try to see if my latest code (posted after Jim's post) does good for you...i tried to avoid using this$0 or anything like that in that code...
regards
maulin
Paul Keohan
Ranch Hand

Joined: Mar 15, 2000
Posts: 411
Hi Maulin.
But does your code involve making a change to the actual outer or inner class? I don't have access to the source code of the class.
Paul
Maulin Vasavada
Ranch Hand

Joined: Nov 04, 2001
Posts: 1871
hi paul,
no my code didn't really require to have the access to the code.
as u can see, i have a object of inner class with me on which i invoke- getClass, getSuperClass, and then getDecalaringClass to get an instance of the outer class and then i invoke a method on that instance...
i guess it would work for u.
regards
maulin.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
 
subject: Accessing Outer Class