groovy/grails を Glassfish-Remote-Client として使用したいのですが、奇妙な ClassLoading の問題が発生しています。
まず、groovy/grails 経由で呼び出されたときにエラーをトリガーするテストコード。Java経由で呼び出された場合は問題ありません。groovy 経由で実行すると、java.lang.ClassCastException がトリガーされます: com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject を javax.rmi.CORBA.PortableRemoteObjectDelegate にキャストできません (PortableRemoteObject.java:77) その前にエラー、そのキャストを手動で行うことは可能です。
==========ソース==========
package test;
import java.lang.reflect.Field;
public class J2EETest {
public static void main(String[] args) throws Exception {
new J2EETest().classLoaderTest();
}
public static void classLoaderTest() throws Exception {
ClassLoader classLoader = J2EETest.class.getClassLoader();
ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader();
System.out.println("classLoader: " + classLoader);
System.out.println("threadClassLoader: " + threadClassLoader);
Class klass = Class.forName( "com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject", false, threadClassLoader );
Object obj = klass.newInstance();
System.out.println("Object -> " + obj.toString());
// This works
javax.rmi.CORBA.PortableRemoteObjectDelegate del = (javax.rmi.CORBA.PortableRemoteObjectDelegate) obj;
try {
System.out.println("Init of javax.rmi.PortableRemoteObject");
// This doesn't work !
System.out.println( Class.forName("javax.rmi.PortableRemoteObject", true, threadClassLoader));
Class prOklass = javax.rmi.PortableRemoteObject.class;
Field staticfield = prOklass.getDeclaredField("proDelegate");
staticfield.setAccessible(true);
System.out.println("Reflection: PortableRemoteObject.proDelegate ->" + staticfield.get(null));
System.out.println("OK");
}
catch(Throwable e) {
System.err.println("BOOM");
e.printStackTrace();
}
}
}
======= JAVA テスト実行 =======
$ export CLASSPATH=build:lib/glassfish/gf-client-module.jar # gf-client-module.jar -> GLASSFISH-Client Libs
$ java -Djavax.rmi.CORBA.PortableRemoteObjectClass=com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject test.J2EETest
classLoader: sun.misc.Launcher$AppClassLoader@e776f7
threadClassLoader: sun.misc.Launcher$AppClassLoader@e776f7
Object -> com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject@5511e28
Init of javax.rmi.PortableRemoteObject class javax.rmi.PortableRemoteObject
Reflection: PortableRemoteObject.proDelegate -> com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject@20e5f01b
OK
======= 今は Groovy バージョン =======
$ groovy -Djavax.rmi.CORBA.PortableRemoteObjectClass=com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject -e "test.J2EETest.classLoaderTest()"
classLoader: org.codehaus.groovy.tools.RootLoader@5dcba031
threadClassLoader: org.codehaus.groovy.tools.RootLoader@5dcba031
Object -> com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject@1bf3f158
Init of javax.rmi.PortableRemoteObject
BOOM
java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at test.J2EETest.classLoaderTest(J2EETest.java:83)
at test.J2EETest$classLoaderTest.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at script_from_command_line.run(script_from_command_line:1)
at groovy.lang.GroovyShell.runScriptOrMainOrTestOrRunnable(GroovyShell.java:266)
at groovy.lang.GroovyShell.run(GroovyShell.java:517)
at groovy.lang.GroovyShell.run(GroovyShell.java:172)
at groovy.ui.GroovyMain.processOnce(GroovyMain.java:553)
at groovy.ui.GroovyMain.run(GroovyMain.java:337)
at groovy.ui.GroovyMain.process(GroovyMain.java:323)
at groovy.ui.GroovyMain.processArgs(GroovyMain.java:120)
at groovy.ui.GroovyMain.main(GroovyMain.java:100)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:108)
at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:130)
Caused by: java.lang.ClassCastException: com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject cannot be cast to javax.rmi.CORBA.PortableRemoteObjectDelegate at javax.rmi.PortableRemoteObject.<clinit>(PortableRemoteObject.java:77)
... 22 more
======= -Djavax.rmi.CORBA.PortableRemoteObjectClass なしの Groovy バージョン =======
これは機能しますが、グラスフィッシュ クライアントのオプションではありません。なぜなら、InitialContext (またはそこにある何か) が javax.rmi.CORBA.PortableRemoteObjectClass = com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject を設定するからです。
$ groovy -e "test.J2EETest.classLoaderTest()"
classLoader: org.codehaus.groovy.tools.RootLoader@3b4d82e1
threadClassLoader: org.codehaus.groovy.tools.RootLoader@3b4d82e1
Object -> com.sun.corba.ee.impl.javax.rmi.PortableRemoteObject@527e2f47
Init of javax.rmi.PortableRemoteObject
class javax.rmi.PortableRemoteObject
Reflection: PortableRemoteObject.proDelegate -> com.sun.corba.se.impl.javax.rmi.PortableRemoteObject@5b3bd1c0 # com.sun.corba.ee != com.sun.corba.se
わかった
誰かが同様の問題を抱えていたり、このコードを機能させる方法を知っていますか?
敬具
フランク