使用附加的classpath选项调用“ java -jar MyFile.jar”


91

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

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)

为什么会这样?

Answers:


151

您可以使用两种 -jar 或者 -cp,你不能将二者结合起来。如果要在类路径上放置其他JAR,则应将它们放在主JAR清单中,然后使用,java -jar或者将完整的类路径(包括主JAR及其依赖项)放入其中,-cp并在命令行上显式命名主类。

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

(我使用的dir/*是告诉java命令将所有.jar文件从特定目录添加到类路径的语法。请注意,*必须使用shell保护它们免受扩展,这就是为什么我使用了单引号。)

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

<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条目。
Himanshu Bhardwaj 2013年

@HimanshuBhardwaj的确,我添加了一个使用该方法的示例<manifestclasspath>
Ian Roberts

“ MyProgram.jar:libs / *”中的“:”是什么分隔符?
Gobliins

@Gobliins冒号是Linux和Mac操作系统下路径中各项之间的分隔符。在Windows上,您应使用分号(;)代替,因为Windows上的冒号用于驱动器号。OP在他们的问题中使用了冒号和正斜杠,表明它们是在Linux或Mac上。
伊恩·罗伯茨

5
如果这些选项是互斥的,则当两个选项同时使用时,命令行应打印警告。谁有时间参加这个琐事?
JJS

22

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

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

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


0

这有点棘手。以下脚本试图从jar清单中获取类路径,然后允许添加额外的类路径条目。我对此有喜忧参半,但仍然希望共享该脚本,因此在这里可以使其完全发挥作用。

该脚本有两个名称

  • 显示清单
  • 卡亚尔

通过将两个文件与

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

-1

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

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

$ ln -s /usr/share/java/swt.jar .
$ java -jar app.jar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.