• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

Accessing Outer Class

 
Ranch Hand
Posts: 411
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Ranch Hand
Posts: 1873
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 411
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


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
 
Maulin Vasavada
Ranch Hand
Posts: 1873
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
hi Michael,
i meant following,

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

regards
maulin.
 
Michael Morris
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
 
Wanderer
Posts: 18671
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
 
Maulin Vasavada
Ranch Hand
Posts: 1873
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


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
Posts: 411
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 3451
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 411
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I'll check that out and make it more generic.
 
Maulin Vasavada
Ranch Hand
Posts: 1873
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 411
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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
Posts: 1873
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
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.
reply
    Bookmark Topic Watch Topic
  • New Topic