【问题标题】:Call "java -jar MyFile.jar" with additional classpath option使用附加类路径选项调用“java -jar MyFile.jar”
【发布时间】:2013-04-02 14:03:16
【问题描述】:

我创建了一个包含所有编译内容的 jar 文件。此外,我的 ant 构建脚本将所需的库复制到子文件夹“库”中。结构如下:

MyProgram.jar
libs/

所以当我现在尝试运行我的程序时,我收到以下错误:

java -cp ".:/home/user/java/MyProgram/jar/libs" -jar MyProgram.jar
java.lang.ClassNotFoundException: org.postgresql.Driver
    at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:186)
    at database.PostgresQL.getConnection(PostgresQL.java:38)
    at recommender.dao.Creative2IdxDAO.createCreatives2Idx(Creative2IdxDAO.java:19)
    at main.Main.calculateCorrelationMatrix(Main.java:51)
    at main.Main.main(Main.java:28)
java.lang.NullPointerException
    at recommender.dao.Creative2IdxDAO.createCreatives2Idx(Creative2IdxDAO.java:25)
    at main.Main.calculateCorrelationMatrix(Main.java:51)
    at main.Main.main(Main.java:28)

为什么会这样?

【问题讨论】:

    标签: java jar classpath


    【解决方案1】:

    你使用 either -jar -cp,你不能将两者结合起来。如果您想在类路径中添加额外的 JAR,那么您应该将它们放在主 JAR 的清单中,然后使用 java -jar 或者将完整的类路径(包括主 JAR 及其依赖项)放在 -cp 中并命名主在命令行上显式分类

    java -cp 'MyProgram.jar:libs/*' main.Main
    

    (我正在使用dir/* 语法告诉java 命令将所有.jar 文件从特定目录添加到类路径。请注意* 必须受到外壳程序扩展的保护,这就是我使用单引号的原因。)

    您提到您正在使用 Ant,因此对于替代清单方法,您可以使用 ant 的 <manifestclasspath> 任务复制依赖项但之前构建 JAR。

    <manifestclasspath property="myprogram.manifest.classpath" jarfile="MyProgram.jar">
      <classpath>
        <fileset dir="libs" includes="*.jar" />
      </classpath>
    </manifestclasspath>
    
    <jar destfile="MyProgram.jar" basedir="classes">
      <manifest>
        <attribute name="Main-Class" value="main.Main" />
        <attribute name="Class-Path" value="${myprogram.manifest.classpath}" />
      </manifest>
    </jar>
    

    有了这个,java -jar MyProgram.jar 将正常工作,并将在类路径中包含所有 libs JAR 文件。

    【讨论】:

    • 添加到上面,或者考虑在MANIFEST.MF文件中添加所需的jar条目。
    • @HimanshuBhardwaj 确实,我添加了一个示例,说明如何使用 &lt;manifestclasspath&gt;
    • 'MyProgram.jar:libs/*' 中的':' 是怎么回事,这是一个分隔符吗?
    • @Gobliins 冒号是 Linux 和 Mac 操作系统下路径中项目之间的分隔符。在 Windows 上,您可以使用分号 (;),因为 Windows 上的冒号用于驱动器号。 OP 在他们的问题中使用了冒号和正斜杠,表明他们在 Linux 或 Mac 上。
    • 如果选项是互斥的,当两者都被使用时命令行应该打印一个警告。谁有时间做这些琐事?!
    【解决方案2】:

    当使用-jar 选项时,-cp 选项将被忽略。设置类路径的唯一方法是使用 jar 中的清单文件。

    使用-cp 选项更容易,将您的 jar 文件添加到其中,然后显式调用主类。

    另外,假设/home/user/java/MyProgram/jar/libs 文件夹包含jar 文件(而不是类文件),这将不起作用。您不能指定 jar 文件的文件夹,但必须在类路径中单独指定每个 jar 文件(如果有大量 jar,则值得编写一个简单的 shell 脚本来为您执行此操作)。

    【讨论】:

    【解决方案3】:

    这有点棘手。以下脚本尝试从 jar 的清单中获取类路径,然后允许添加额外的类路径条目。我对此有好坏参半的结果,但仍想分享脚本,以便它可以在这里完全发挥作用。

    脚本有两个名字

    • 演出清单
    • calljar

    通过将两个文件硬链接在一起 与

    ln calljar showmanifest
    

    用 calljar -h 可以看到用法。

    #!/bin/bash
    #set -x
    # show the manifest of a jar file
    # 2012-07-18
    # author WF
    
    #
    # show usage
    #
    usage() {
     echo "usage: showmanifest (jarfile | directory jarfile) " 1>&2
     echo "usage: calljar directory jarfile classpath pattern arguments" 1>&2
     echo "             -h|--help " 1>&2
     echo "               show this help and exit" 1>&2
     echo "             -m|--mainclass javaclass" 1>&2
     echo "               mainclass to use (otherwise manifest is inspected)" 1>&2
     exit 1
    }
    
    #
    # show the manifest of the given jar file
    #
    show() {
      dir="$1"
      jar="$2"
        fulljar=`find "$dir" -name "$jar"`
        cd /tmp
        mkdir show$$
        cd show$$
        jar xvf $fulljar META-INF/MANIFEST.MF
        cat META-INF/MANIFEST.MF
        cd /tmp
        rm -rf show$$
    }
    
    #
    # show the classpath of the manifest
    #
    calljar() {
      dir="$1"
        jar="$2"
        classpath="$3"
        pattern="$4"
        arguments="$5"
        cmd=`show "$dir" "$jar"   | awk -v extracp="$classpath" -v dir="$dir" -v pattern="$pattern" -v jar="$jar" -v mainclass="$mainclass" -v args="$arguments" '
    /Main-Class: / { if (mainclass=="") mainclass=$2 }
    /^Class-Path:/ { 
      incp=1; 
        cp=$0; 
        gsub("Class-Path: ","",cp) 
        next
    }
    /^ .*$/ && incp { 
        line=substr($0,2)
      # remove carriage return (if any)
      cp=cp line
    }
    END { 
      # we do not like carriage returns
      gsub("\\r","",cp)
      gsub("\\r","",mainclass)
        # we do not like blanks ...
      gsub(" ","",cp)
        gsub(pattern,":"dir"/"pattern,cp)
      print "java -cp " extracp cp ":"dir"/"jar " " mainclass " " args
    }
        '`
      #echo $cmd
        $cmd
    }
    
    
    # echo $# arguments found: $*
    # parse command line options
    while true; do
    # echo "option $1"
      case "$1" in
        # options without arguments
        -h|--help) usage;;
             # for options with required arguments, an additional shift is required
            -m|--mainclass) mainclass=$2; shift;;
          (--) shift; break;;
          (-*) echo "$0: error - unrecognized option $1" 1>&2; usage;;
        (*) dir=$1;shift;break;;
      esac
      shift
    done
    
    #echo "argcount=$#"
    case  $# in
      0) dir=`dirname "$dir"`
           jar=`basename "$dir"`
             show "$dir" "$jar";;
      1) jar="$1"
             show "$dir" "$jar";;
      2) usage;;
        3) usage;;
      *) jar="$1"; shift;
             classpath="$1"; shift;
             pattern="$1"; shift;
             arguments="$@";
        #echo "mainclass=${mainclass}"
        #echo "classpath=${classpath}"
    
      #echo calljar "${dir}" "${jar}" "${classpath}" "$pattern" "$arguments"
        calljar "$dir" "$jar" "$classpath" "$pattern" "$arguments"
        ;;
    esac
    

    【讨论】:

      【解决方案4】:

      为了对应用进行快速的一次性测试,您可以简单地将所需的依赖 JAR 文件符号链接到包含主应用 JAR 文件的目录中。

      示例(对于使用 Eclipse SWT 库的应用程序 app.jar,在我的情况下安装在 /usr/share/java 中):

      $ ln -s /usr/share/java/swt.jar .
      $ java -jar app.jar
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-03
        • 2014-03-21
        • 2016-08-31
        相关资源
        最近更新 更多