【问题标题】:Confusion defining the Main-Class in ant for bundling a jar在 ant 中定义 Main-Class 以捆绑 jar 的困惑
【发布时间】:2012-01-10 22:52:44
【问题描述】:

我正在尝试使用 Amazon Mechanical Turk API 构建一个 jar 文件。 SDK 附带一个 helloworld 文件,我试图将其作为健全性检查 - 它位于此处:

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

设置完所有内容后,我可以使用提供的 build.xml 文件使用 ant 正确构建和执行。

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 可由其他人执行,而无需安装库。看起来“正确”的方法是从 ant 内部构造一个 jar。

我的理解是我需要包括:

  • 必要的库,从 sdk 本身构建(并作为 .jar 提供)
  • 构建的 helloworld 类文件
  • 清单属性指定要运行的主类

我不知道是否需要添加其他内容。我知道运行时有一个大而复杂的类路径,我可以在命令行上指定类路径,但我怀疑对类路径进行硬编码会阻止我分发 .jar 文件,这就是重点。

这是 jar 的 build.xml sn-p:

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

这样构建。但是,当我运行 jar 时,它会崩溃:

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 中的文件:

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

这表明如果将类路径设置为 build/private/classes/samples/ 可能会正常工作:

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

这会导致相同的错误。我认为我在这里缺少一些非常基本的东西,我将不胜感激!

【问题讨论】:

    标签: java ant jar classpath mechanicalturk


    【解决方案1】:

    你的package-folder必须直接启动,不能放在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 是编译包的来源。 使用&lt;fileset /&gt;,您只需添加普通文件即可。

    此外,您不能将外部库放入 jar 文件中。它们必须与 jar 位于同一文件夹中、java classpath 或清单的 classpath-attribute 指定的文件夹中。 或者您可以使用one jar task,将类包含到您的 jar 中。

    【讨论】:

    • 您认为在这种情况下最好的做法是什么?制作一个 jar(使用一个 jar),或者只是给出指示告诉人们安装包本身并制作 ant 任务来运行东西?
    • @alexplanation 说明总是可能被误读。我建议(如果您直接将其提供给最终用户)一个 zip 文件(包含所有内容,只需解压缩)。或者 onejar 方法。
    猜你喜欢
    • 2012-03-06
    • 2015-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    相关资源
    最近更新 更多