UnsatisfiedLinkError in GWTTestCase.<clinit>

384 views
Skip to first unread message

Mat Gessel

unread,
Aug 14, 2006, 10:13:57 PM8/14/06
to GWT Group
Happens if you have a static initializer in the test case which calls
a JSNI native method.
Also happens if you call the native method in TestCase.setUp().

You have to run the TC in hosted mode.

Workaround: call the native method in the test method.

I use the same JSNI initialization pattern in real applications and it
works fine.


Code example:
public class StaticJSNIInitializer extends GWTTestCase
{
static
{
jsInit();
}

private static native void jsInit() /*-{
// define a native function to call into GWT
}-*/;

public String getModuleName()
{
return "asquare.gwt.bugs.UnitTests";
}

public void testSimple()
{
// workaround: do JSNI initialization here

assertEquals(true, true);
}
}


Stack trace:
java.lang.UnsatisfiedLinkError: jsInit
at asquare.gwt.bugs.test.StaticJSNIInitializer.jsInit(Native Method)
at asquare.gwt.bugs.test.StaticJSNIInitializer.<clinit>(StaticJSNIInitializer.java:24)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:274)
at junit.framework.TestSuite.createTest(TestSuite.java:131)
at junit.framework.TestSuite.addTestMethod(TestSuite.java:114)
at junit.framework.TestSuite.<init>(TestSuite.java:75)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.getTest(RemoteTestRunner.java:399)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:445)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Exception in thread "main"

--
Mat Gessel
http://www.asquare.net

Scott Blum

unread,
Aug 14, 2006, 10:50:23 PM8/14/06
to Google Web Toolkit
Hi Mat,

You're quite right about this one, but I'm not sure there's any really
good alternatives. The problem is that your test case actually has to
serve two distinct roles. First, the compiled class file must be a
real JUnit TestCase so that it will fit into the JUnit framework
properly; the launch sequence for your test case turns around and
launches the JUnitShell which creates a hosted mode or web mode
environment to actually run the real test. Meanwhile, the source code
for you test case then serves in the second role, to be translated and
run inside the browser. The problem you point out lies in the conflict
between these two competing goals. A workaround could be to compile a
stripped-down class file that does not use natives, but couple it with
a source file that does. But that would force you to keep things
out-of-sync. If anyone has ideas on how to reformulate this to loosen
the restrictions, I'd be interested.

Scott

Konstantin Scheglov

unread,
Aug 15, 2006, 12:17:44 AM8/15/06
to Google Web Toolkit
Sorry If I don't understand something, but:

1. As I can see from stack trace above and from generated
Test-hosted.cmd, you just run junit.textui.TestRunner. So, most
probably it really just loads classes from disk.

2. Why not run something more complex, like mentioned JUnitShell (I
don't know what it does, probably something like GWTShell) that:
- initializes Tomcat;
- creates special class loader for JUnit and application classes;
- loads JUnit runner using this class loader and runs it.

Because you run JUnit from your class loader, it will ask for classes
using it, so you will able to replace "native" methods with something
executable. And you probably already have such kind of class loader for
GWTShell.

Scott Blum

unread,
Aug 15, 2006, 11:31:49 AM8/15/06
to Google Web Toolkit
Konstantin,

The problem is that GWT has no chance to gain control of the system
before the error occurs. Look at the stack trace carefully and you'll
see that every method on the stack is a JUnit framework method right up
to the point where the user's class is being initialized. There's
simply no opportunity that I'm aware of to step in and hijack the
process until *after* clinit and such, because we're implemented as a
superclass of the user's class.

Scott

Konstantin Scheglov

unread,
Aug 15, 2006, 11:46:44 AM8/15/06
to Google Web Toolkit
Ok, now I understand. You want to keep using standard JUnit running
way, i.e. for example junit.textui.TestRunner, or runner from Eclipse.
But you need way change preprocess classes before they will be loaded
by JVM.

This is known problem during writing of profilers. Before Java5 only
was was using native library. In Java5 you can write agents on Java.
See following option:

-javaagent:<jarpath>[=<options>]
load Java programming language agent, see
java.lang.instrument

You can generate required .cmd files to run JUnit tests with agent
and users of IDE's can add this parameter manually. At least Eclipse
allows this. Later, developers of GWT supporting plugins can add
special launch configuration type that will add such parameters
automatically.

Reply all
Reply to author
Forward
0 new messages