I’m trying to construct a jar file using the Amazon Mechanical Turk API. The SDK comes with a helloworld file that I’m trying to jar up as a sanity check – it is located here:
http://aws.amazon.com/code/SDKs/695
After setting everything up, I’m able to use ant to build and execute correctly, using the supplied build.xml file.
bash-3.2$ ant helloworld
ant helloworld
Buildfile: /Users/astorer/Work/dtingley/java-aws-mturk-1.2.2/build.xml
compile-sample:
[echo] Compiling the sample java source files...
[javac] /Users/astorer/Work/dtingley/java-aws-mturk-1.2.2/build.xml:252: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds
helloworld:
[echo] Running the Hello World sample application...
[java] Got account balance: 10000.00
[java] Created HIT: 2RB2D5NQYN5F41KJ2IKYPNCW2H3A60
[java] You may see your HIT with HITTypeId '22R58B727M0IHQ4HZEXYISVF4XCWBC' here:
[java] http://workersandbox.mturk.com/mturk/preview?groupId=22R58B727M0IHQ4HZEXYISVF4XCWBC
[java] Success.
BUILD SUCCESSFUL
Total time: 11 seconds
I want the helloworld to be executable by someone else without needing to install the libraries. It seems like the “correct” way to do this is to construct a jar from within ant.
My understanding is that I need to include:
- the necessary libraries, build from the sdk itself (and provided as a .jar)
- the built helloworld class file
- the manifest attribute specifying the main class to run
I don’t know if I need to include anything else. I know that there is a big, complicated classpath at runtime, and that I can specify the classpath on the command line, but I suspect hard coding the classpath will prevent me from distributing the .jar file, which is the entire point.
Here is the build.xml snippet for the jar:
<target name="hellojar" depends="helloworld" description="Creates Jar of helloworld" >
<jar destfile="helloworld.jar">
<fileset file="${sdk.jar}" />
<fileset dir="${sample.classes.dir}/helloworld/" />
<fileset dir="."/>
<manifest>
<attribute name="Main-Class" value="MTurkHelloWorld" />
</manifest>
</jar>
</target>
This builds. When I run the jar, it crashes, however:
bash-3.2$ java -jar helloworld.jar
java -jar helloworld.jar
Exception in thread "main" java.lang.NoClassDefFoundError: MTurkHelloWorld (wrong name: helloworld/MTurkHelloWorld)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631)
at java.lang.ClassLoader.defineClass(ClassLoader.java:615)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
This makes sense, because my MTurkHelloWorld is actually in the helloworld package. Thus, I should change to:
<manifest>
<attribute name="Main-Class" value="helloworld.MTurkHelloWorld" />
</manifest>
This builds successfully. When I run it:
bash-3.2$ java -jar helloworld.jar
java -jar helloworld.jar
Exception in thread "main" java.lang.NoClassDefFoundError: helloworld/MTurkHelloWorld
Caused by: java.lang.ClassNotFoundException: helloworld.MTurkHelloWorld
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
We can investigate the files within the jar:
jar tf helloworld.jar | grep hello
build/private/classes/samples/helloworld/
samples/helloworld/
build/private/classes/samples/helloworld/MTurkHelloWorld.class
samples/helloworld/MTurkHelloWorld.java
Which suggests that maybe if the classpath were set to build/private/classes/samples/ it would work properly:
<attribute name="Class-Path" value="build/private/classes/samples/helloworld" />
This leads to an identical error. I think there is something pretty fundamental that I’m missing here, and I’d appreciate any help!
Your package-folder have to start directly, you can’t put them in any sub-directory in the jar file:
It would have to look like this:
Your jar-task would have to look like this:
The basedir is the source of your compiled packages.
With
<fileset />you just add normal files.Furthermore, you can’t put external libs into jar files. They have to be in the same folder as the jar, in the
java classpathor in a folder specified by theclasspath-attributeof the manifest.Or you could use the one jar task, to include the classes into your jar.