Путаница в определении основного класса в муравье для упаковки банки - PullRequest
3 голосов
/ 01 декабря 2011

Я пытаюсь создать файл jar с помощью Amazon Mechanical Turk API. SDK поставляется с файлом helloworld, который я пытаюсь собрать в качестве проверки работоспособности - он находится здесь:

http://aws.amazon.com/code/SDKs/695

После настройки я могу использовать ant для правильной сборки и выполнения, используя прилагаемый файл build.xml.

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

Я хочу, чтобы helloworld мог выполняться кем-то другим без установки библиотек. Кажется, что «правильный» способ сделать это - создать банку из муравья.

Насколько я понимаю, мне нужно включить:

  • необходимые библиотеки, собранные из самого SDK (и предоставленные в виде .jar)
  • встроенный файл класса helloworld
  • атрибут манифеста, определяющий основной класс для запуска

Я не знаю, нужно ли мне что-то еще включать. Я знаю, что во время выполнения есть большой и сложный путь к классам, и что я могу указать путь к классам в командной строке, но я подозреваю, что жесткое кодирование пути к классам не позволит мне распространять файл .jar, который и составляет весь смысл.

Вот фрагмент build.xml для фляги:

  <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>

Это строит. Когда я запускаю флягу, она вылетает, однако:

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)

Это имеет смысл, потому что мой MTurkHelloWorld фактически находится в пакете helloworld. Таким образом, я должен изменить на:

  <manifest>
    <attribute name="Main-Class" value="helloworld.MTurkHelloWorld" />
  </manifest>

Это успешно строится. Когда я запускаю его:

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)

Мы можем исследовать файлы в банке:

jar tf helloworld.jar | grep hello
build/private/classes/samples/helloworld/
samples/helloworld/
build/private/classes/samples/helloworld/MTurkHelloWorld.class
samples/helloworld/MTurkHelloWorld.java

Что говорит о том, что, возможно, если бы classpath был установлен для сборки / private / classes / samples /, он бы работал правильно:

<attribute name="Class-Path" value="build/private/classes/samples/helloworld" />

Это приводит к идентичной ошибке. Я думаю, что здесь есть что-то довольно фундаментальное, что мне не хватает, и я был бы признателен за любую помощь!

1 Ответ

3 голосов
/ 02 декабря 2011

Ваша папка-пакет должна запускаться напрямую, вы не можете поместить их в любой подкаталог в файле jar:

Это должно выглядеть так:

helloworld/
helloworld/MTurkHelloWorld.class

Ваш jar-task должен выглядеть следующим образом:

<jar destfile="helloworld.jar" basedir="${sample.classes.dir}">>
  <manifest>
    <attribute name="Main-Class" value="MTurkHelloWorld" />
  </manifest>
</jar>

Basedir - это источник ваших скомпилированных пакетов. С <fileset /> вы просто добавляете обычные файлы.

Кроме того, вы не можете помещать внешние библиотеки в файлы JAR. Они должны находиться в той же папке, что и jar, в java classpath или в папке, указанной classpath-attribute в манифесте. Или вы можете использовать задачу one jar , чтобы включить классы в вашу банку.

...