views:

94

answers:

4

I am trying to use Reflection on the server side only of a GWT app. I have a basic example working in a non-GWT example which can be seen below.

package com.xyz.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class EntryPoint {

/**
 * @param args
 */
public static void main(String[] args) {

    ClassLoader dynClassLoader = ClassLoader.getSystemClassLoader();

    Class<?> dynClass = null;
    try {
        dynClass = dynClassLoader.loadClass("com.xyz.reflection.RunMe");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    Object dynInstance = null;
    try {
        dynInstance = dynClass.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

    Method dynMethod = null;
    try {
        try {
            dynMethod = dynInstance.getClass().getMethod("returnSid",
                    new Class[] { PassMe.class });

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        String returnValue = (String) dynMethod.invoke(dynInstance,
                new Object[] { new PassMe() });

        System.out.println("Return Value: " + returnValue.toString());

    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

}

using the aptly named:

    package com.xyz.reflection;

public class PassMe {

private String sid = "DEFAULT_SID";

public PassMe() {
    this.sid = "INITIATED_SID";
}

public String getSid() {
    return sid;
}

public void setSid(String sid) {
    this.sid = sid;
}

}

and:

    package com.xyz.reflection;


public class RunMe {

    public String returnSid(PassMe s) {
        return s.getSid();
    }
}

This runs fine. When I try running this from a GWT server side class it doesn't work, and instead returns

 java.lang.NoSuchMethodException: com.xyz.reflection.RunMe.returnSid(com.xyz.reflection.PassMe)

If I change the parameter to a String (instead of the 'PassMe' class) it works fine. Why does it not like passing my 'PassMe' class? I thought it might be an issue with serialization despite being 100% server code, but I haven't had any luck with this either.

Thanks in advance for any help anyone can give me with this.

A: 

This is pretty much a shot in the dark, but does it help if you replace dynMethod = dynInstance.getClass().getMethod("returnSid", new Class[] { PassMe.class });

with

dynMethod = dynInstance.getClass().getMethod("returnSid", PassMe.class ); ?

It doesn't make a difference outside of a GWT server, but it may exercise the container's VM differently.

Curtis
Nice try but no cigar. Unfortunately this seems to makes no difference; but thanks very much for sparing time in trying to help.
specialtrevor
A: 

Did you put your reflection file in the server side package? For example:
org.myproject.client - your gwt client package (put here your java files that are able to be complied into java script NO REFLECTION)
org.myproject.server - put here any java files including reflection
org.myproject.shared - put here java classes that are able to be compiled into java script

kospiotr
I have tried with the reflection code being in 'org.myproject.server' and in 'org.external.reflection' (including the external project/package in the build path) and neither make a difference.To confirm, neither are in the *.gwt.xml file for client source path. This remains as: <source path='client'/> <source path='shared'/>Thanks for your time.
specialtrevor
+1  A: 

I think this could be related to Class loading - but it is just a hunch as I cannot experiment with it in context similar to yours.

Here are some suggestions to try:

You use:

ClassLoader dynClassLoader = ClassLoader.getSystemClassLoader();

dynClass = dynClassLoader.loadClass("com.xyz.reflection.RunMe");

To load the RunMe Class.

However to load the PassMe class you use:

PassMe.class

Try to load the PassMe Class through the dynClassLoader and use that instance in the getMethod() instead of the PassMe.class.

I wonder, do you need to use the dynClassLoader?

finrod
This one had me curious so I tried it out. If you use the same loader to instantiate PassMe, it works fine. Probably has a lot to with GWT's secret RPC sauce.
j flemm
+1  A: 

In addition to finrod's solution, you can also change your class loader to something like:

ClassLoader dynClassLoader = PassMe.class.getClassLoader();

And you can use the PassMe.class style lookup again. The class used to find a loader doesn't seem to matter though. Just not the system loader.

Weird stuff. I wouldn't doubt if GWT is doing something weird with the class loader though.

Edit: Yep. GWT sets the system class loader to com.google.appengine.tools.development.IsolatedAppClassLoader in dev mode.

j flemm
Perfect! All I had to change was the line you've highlighted and it works like a dream. Thanks to yourself and to finrod who got the ball rolling. +1 for you both :o)Sorry for the delayed response, I've been away on holiday.For further reading on class paths I found this old yet informative article: http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html?page=1
specialtrevor