Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Problem: Calling methods of dynamically loaded inner classes at runtime

Reply
Thread Tools

Problem: Calling methods of dynamically loaded inner classes at runtime

 
 
Thea
Guest
Posts: n/a
 
      08-01-2006
Hello
I need some help ^^

While trying to dynamically load class and use it I have come across a
problem that prevents any progress.
I have a class that contains some inner classes (and I can't change
this design). From outer class (called Test) I need to call inner
classes at runtime. (inner classes are called XXXTest)

I am using following code to read name of a class to be loaded and load
it.
Name of a class comes as a String in form of "package.Test$XXXTest"
from configuration file.

Map attrs = page.getAttributes(); //here I get names of
classes to be loaded
//names are obtained correctly, checked that (correctly==as provided in
config file)

for (Object o : attrs.keySet())
{
try {
Class attributeClass = Class.forName(o.toString());
Constructor attributeCon =
attributeClass.getConstructor();
Object attributeObject =
attributeCon.newInstance();

//making sure that calling execute routine makes sense
if (attributeObject instanceof Module)
((Module)attributeObject).execute(page, request,
response);

} catch (Exception e) {
e.getMessage();
}
}
//This code is executed in class Test, and all loded classes are inner
to Test

Problem is that though compiler shows no error, it doesn't seem to run
'execute' method of the inner class (any of them). I set some debug
info in each inner class 'execute' method, but it simply won't appear
on output and page context is empty (results are put out on page)
'Funny' thing is that when I call it this way:
CP2Test cp2 = new CP2Test();
cp2.execute(page,request, response);
it works... (CP2Test is one of the inner classes)
But I can't do this... it must be done dynamically.
I've been through FAQ but could find nothing...
Is there something wrong with my code? Did I miss something important?
Thank you for time you spent reading my question.

 
Reply With Quote
 
 
 
 
Chris Uppal
Guest
Posts: n/a
 
      08-01-2006
Thea wrote:

> } catch (Exception e) {
> e.getMessage();
> }


You seem to be discarding errors silently -- not the best way to find out
what's going wrong


> //making sure that calling execute routine makes sense
> if (attributeObject instanceof Module)
> ((Module)attributeObject).execute(page, request,


Again, you are supressing errors silently. The guard test may make sense for
deployed code but it is /currently/ preventing you from seeing any errors.
Actually, unless the design requires cases where the loaded classes may not
implement Module, then the test would probably be unwise even in deployed
code -- for exactly the same reason.


> Map attrs = page.getAttributes(); //here I get names of
> classes to be loaded
> //names are obtained correctly, checked that (correctly==as provided in
> config file)


It's possible that you are specifying the wrong names for the inner classes.
The /real/ name of a class defined as:

package my.stuff;
class Outer
{
class Inner { }
}

is something like my.stuff.Outer$Inner. See the name of the classfile to see
what you /should/ be providing.


Also:

> Constructor attributeCon = attributeClass.getConstructor();
> Object attributeObject = attributeCon.newInstance();


If your "inner" classes really are inner, rather than just static nested
classes, then none of them will have a no-args constructor. All non-static
nested classes require a pointer to their outer object, and that is passed in
as a (hidden) parameter to each constructor, which is added by javac. When you
call the constructor in normall code the compiler automatically adds a ref to
the outer object to the parameters you pass -- but if can't do that when you
are using reflection.

Given that you expect the above to work at all, it sounds as if your design
really calls for the nested classes to be static, in which case your use of
Constructors should work as is. If not then you'll have to change the
reflective code accordingly.

-- chris


 
Reply With Quote
 
 
 
 
Thea
Guest
Posts: n/a
 
      08-01-2006
> You seem to be discarding errors silently -- not the best way to find out
I changed catch block so that it handles each error separately and
removed the condition.
Still, no error appeared

> It's possible that you are specifying the wrong names for the inner classes.

Checked that too, here everything is fine...

> Also:
>
> Constructor attributeCon = attributeClass.getConstructor();
> Object attributeObject = attributeCon.newInstance();
>
> If your "inner" classes really are inner, rather than just static nested
> classes, then none of them will have a no-args constructor. All non-static
> nested classes require a pointer to their outer object, and that is passed in
> as a (hidden) parameter to each constructor, which is added by javac. When you
> call the constructor in normall code the compiler automatically adds a ref to
> the outer object to the parameters you pass -- but if can't do that when you
> are using reflection.


Well, classes are inner, and I rather cannot make them static, because
in all cases ececute() is using non-static variables being fields of
outer class...
If I try to make inner classes static, environment says that you cannot
reference non-static variable from static content...
Do you have any idea how to get that magic pointer to outer object and
pass it?... Or maybe how to make it accept such reference?...

I also played a little bit more with the code
and for such code

Map attrs = page.getAttributes();
for (Object o : attrs.keySet())
{
try {
1) Class attributeClass =
Class.forName(o.toString());
2) log.info("AAAA"+attributeClass.toString());
3) Constructor attributeCon =
attributeClass.getConstructor();
4) log.info("BBBB"+attributeCon.toString());
5) Object attributeObject =
attributeCon.newInstance();
6) log.info("CCCC"+attributeObject.toString());
7) ((Module)attributeObject).execute(page, request,
response);


}
catch (InstantiationException e) {e.getMessage();}
catch (IllegalAccessException e) {e.getMessage();}
catch (InvocationTargetException e) {e.getMessage();}
catch (NoSuchMethodException e) {e.getMessage();}
catch (ClassNotFoundException e) {e.getMessage();}
}

got output:
[2006-08-01 12:20:33,570] INFO [Test] AAAAclass
com.cp2portal.util.Test$CP2Test
[2006-08-01 12:20:33,576] INFO [Test] AAAAclass
com.cp2portal.util.Test$MailTest
It seems not to execute code from line 3-7. Anything that is outside
try-catch block works fine.No errors appeared...
I'm really confused.

 
Reply With Quote
 
Gordon Beaton
Guest
Posts: n/a
 
      08-01-2006
On 1 Aug 2006 03:24:01 -0700, Thea wrote:
> I changed catch block so that it handles each error separately and
> removed the condition. Still, no error appeared


[...]

> catch (InstantiationException e) {e.getMessage();}
> catch (IllegalAccessException e) {e.getMessage();}
> catch (InvocationTargetException e) {e.getMessage();}
> catch (NoSuchMethodException e) {e.getMessage();}
> catch (ClassNotFoundException e) {e.getMessage();}


That's because e.getMessage() does not display anything, as you seem
to think it does. Try using e.printStackTrace() instead.

/gordon

--
[ don't email me support questions or followups ]
g o r d o n + n e w s @ b a l d e r 1 3 . s e
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      08-01-2006
Thea wrote:

> I changed catch block so that it handles each error separately and
> removed the condition.
> Still, no error appeared


But you still seem just to be calling e.getMessage() -- that has no effect
except to return a String, which you discard. Try logging the returned value,
or using e.printStackTrace() instead, or something.


> Do you have any idea how to get that magic pointer to outer object and
> pass it?... Or maybe how to make it accept such reference?...


You have to /decide/ which instance(s) of the outer class you want these
objects to refer to. That to say: /which/ outer object's fields you want them
to have access to. Please do note that this is an /extremely/ important
aspect of your design -- it isn't just a trivial messing around in order to
satisfy petty-fogging restrictions in the compiler!

Once you have decided which object(s) you want the inner class instance to
refer to, you just pass a reference to it (or them) to the inner classes'
constructors.

-- chris




 
Reply With Quote
 
Thea
Guest
Posts: n/a
 
      08-01-2006
e.printStackTrace() worked fine ^^ thanks for this advice ^^ Now I'll
remember that getMessage() is not the best choice ever ^^'.
I got NoSuchMethodException...
I suppose it's because of getting the constructor - error appears on
line

Constructor attributeCon = attributeClass.getConstructor();

I have decided which fields of outer class will be accessed and turned
them static.
I also had to add static reference to outer class, as inner class uses
one of the outer class inherited methods...
Now I'm not sure how to pass arguments in line above. I don't really
understand notation used in documentation:

public Constructor<T> getConstructor(Class... parameterTypes)

it says it should be array of parameters... though I have no idea how
to create it (I mean, what type(s) should I use) I tried several things
but I don't seem to catch the idea...

 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      08-01-2006
Thea

Please don't take this as an insult, but you seem to be a little out of your
depth. Reflective programming requires a good understanding of the
fundamentals of Java, which perhaps you are not as strong on yet as you need to
be.

Anyway, I've put together a little working example, which maybe will help you
to sort this stuff out. I'll put it at the end of this message.

> Constructor attributeCon = attributeClass.getConstructor();


One potential problem here (and I admit it's a bit obscure -- I had forgotten
all about it until I tried it just now), is that if your nested or inner
classes have a default constructor (you don't define one explicitly) the one
that javac creates for you is not public unless the nested classes are public
themselves. So, if that's the situation, you will have to use
Class.getDeclaredConstructor() instead of Class.getConstructor(), since the
latter only lists public constructors.

Javac always does create a default constructor if none is defined explicitly,
for any kind of class (not just nested), but it takes its access from the
class. If the class is nested /and/ declared private, then javac does
something even more odd and inconvenient -- which I hope you won't need to
worry about; we'll deal with that if we have to.


> public Constructor<T> getConstructor(Class... parameterTypes)
>
> it says it should be array of parameters... though I have no idea how
> to create it (I mean, what type(s) should I use) I tried several things
> but I don't seem to catch the idea...


If you are passing an array then the elements should be the java.lang.Class
objects corresponding to the parameter types. If you know the class in advance
then its easiest to use a "class literal", something like
String.class
which evaluates to the class object for java.lang.String. Since
getConstructor() had been retrofitted to use variadic parameter lists (which
just means that the compiler builds and initialises the array for you from the
parameters you supply when you call it), you can write, for instance:
cl.getConstructor(Class1.class, Class2.class, Integer.class);
rather than having to create an array explicitly.

-- chris


========== Outer.java ============
interface Doable
{
void doit();
}

public class Outer
{
private static String staticField = "(static in class Outer)";
private String instanceName;

Outer(String str)
{
instanceName = str;
}

static class StaticNested
implements Doable
{
public void
doit()
{
System.out.printf("\tdoit called from %s%n", this);
System.out.printf("\tstaticField = %s%n", staticField);
System.out.println();
}
}

class Inner
implements Doable
{
public void
doit()
{
System.out.printf("\tdoit() called from %s%n", this);
System.out.printf("\tstaticField = %s%n", staticField);
System.out.printf("\tinstanceName = %s%n", instanceName);
System.out.println();
}
}

void
example()
throws Throwable // only to keep the example short !!
{
System.out.printf("*** I am %s ***%n", instanceName);

System.out.println("exampleWithoutReflection()");
exampleWithoutReflection();
System.out.println("exampleWithReflection()");
exampleWithReflection();

System.out.println("**** End ***");
}

void
exampleWithoutReflection()
{
new StaticNested().doit();
new Inner().doit();
}

void
exampleWithReflection()
throws Throwable // only to keep the example short !!
{
Class cl;
java.lang.reflect.Constructor ctor;
Doable doable;

// NB: we have to use getDeclaredConstructor()
// instead of getConstructor() since the implicit
// ctors for the nested classes are not public

// static nested class
cl = Class.forName("Outer$StaticNested");
ctor = cl.getDeclaredConstructor();
doable = (Doable)ctor.newInstance();
doable.doit();

// inner class, we have to pass ourself to the ctor
cl = Class.forName("Outer$Inner");
ctor = cl.getDeclaredConstructor(Outer.class);
doable = (Doable)ctor.newInstance(this);
doable.doit();
}

public static void
main(String[] args)
throws Throwable // only to keep the example short !!
{
Outer joan = new Outer("Joan");
Outer fred = new Outer("Fred");

joan.example();
fred.example();
}
}
==========================


 
Reply With Quote
 
Thea
Guest
Posts: n/a
 
      08-02-2006
Chris, I'm not going to take truth as an insult ^^'
I really didn't get this all as I should... (btw. I had to chceck this
phrase ^^'' ). I have programmed in Java some stuff, but never needed
those mechanisms...
And, to be honest that was my first trial to do such thing...

Thank you for example.
That was what I needed to better understand what I am trying to do.

I thought I will have to make inner classes static AND private, but
with your example I could ommit static which made it much simpler.
So finally it works ^^

Thanks again
Thea

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
failing to instantiate an inner class because of order of inner classes Pyenos Python 2 12-27-2006 11:19 PM
java -verbose doesn't show "loaded from" for classes loaded from custom jars in the classpath Udo Corban Java 0 01-23-2004 09:32 AM
How to access inner classes variables & methods from outer classes lonelyplanet999 Java 1 11-13-2003 01:54 PM
Java inner classes and static methods Neil Zanella Java 1 10-27-2003 01:45 PM
inner classes in python as inner classes in Java Carlo v. Dango Python 14 10-19-2003 08:49 AM



Advertisments