추가 클래스 경로 옵션을 사용하여 "java -jar MyFile.jar"호출


93

모든 컴파일 된 내용을 포함하는 jar 파일을 만들었습니다. 또한 내 ant 빌드 스크립트는 필요한 libs를 하위 폴더 "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)

왜 이런 일이 발생합니까?

답변:


153

당신은 사용 -jar 또는 -cp 당신은 두 가지를 결합 할 수 없습니다. 추가 JAR을 클래스 경로에 넣으려면 기본 JAR의 매니페스트에 넣은 다음 사용 java -jar하거나 전체 클래스 경로 (기본 JAR 및 해당 종속성 포함)를 입력 -cp하고 명령 줄에서 명시 적으로 기본 클래스의 이름을 지정해야합니다.

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

(저는 특정 디렉터리의 모든 파일을 클래스 경로 에 추가 dir/*하도록 java명령에 지시 하는 구문을 사용하고 있습니다 .jar. *은 셸에 의한 확장으로부터 보호되어야하므로 작은 따옴표를 사용했습니다.)

Ant를 사용하고 있으므로 대체 매니페스트 접근 방식의 경우 종속성 복사 한 JAR을 빌드 하기 전에 ant의 <manifestclasspath>작업 사용할 수 있다고 언급했습니다 .

<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>
이안 로버츠

'MyProgram.jar : libs / *'의 ':'는 무엇입니까? 이것은 구분자입니까?
Gobliins 2015 년

@Gobliins 콜론은 Linux 및 Mac 운영 체제에서 경로에있는 항목 사이의 구분 기호입니다. Windows ;에서는 드라이브 문자에 콜론이 사용되므로 Windows 에서는 세미콜론 ( )을 대신 사용합니다. OP는 질문에 콜론과 슬래시를 사용하여 Linux 또는 Mac에 있음을 나타냅니다.
Ian Roberts

5
옵션이 상호 배타적이면 둘 다 사용할 때 명령 줄에서 경고를 인쇄해야합니다. 누가이 퀴즈를 할 시간이 있습니까?!
JJS

22

-jar옵션이 사용되는 -cp옵션은 무시됩니다. 클래스 경로를 설정하는 유일한 방법은 jar의 매니페스트 파일을 사용하는 것입니다.

-cp옵션을 사용하고 여기에 jar 파일을 추가 한 다음 명시 적으로 기본 클래스를 호출하는 것이 더 쉽습니다 .

또한 /home/user/java/MyProgram/jar/libs폴더에 jar 파일이 포함되어 있다고 가정하면 (클래스 파일과 반대) 작동하지 않습니다. jar 파일의 폴더를 지정할 수는 없지만 클래스 경로에서 각 jar 파일을 개별적으로 지정해야합니다 (중요한 수의 jar가있는 경우이를 수행하기 위해 간단한 쉘 스크립트를 작성하는 것이 좋습니다).


0

약간 까다 롭습니다. 다음 스크립트는 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

-1

앱의 빠른 일회성 테스트를 위해 필요한 종속성 JAR 파일을 기본 앱 JAR 파일이 포함 된 디렉토리에 심볼릭 링크하기 만하면됩니다.

예제 ( app.jar내 경우에는에 설치된 Eclipse SWT 라이브러리를 사용 하는 앱의 경우 /usr/share/java) :

$ ln -s /usr/share/java/swt.jar .
$ java -jar app.jar
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.