2013-04-10 39 views
50

Tôi đã tạo tệp jar chứa tất cả nội dung đã biên dịch của mình. Ngoài ra kịch bản xây dựng kiến ​​của tôi sao chép các thư viện yêu cầu vào một thư mục con "libs". Cấu trúc trông như thế này:Gọi "java -jar MyFile.jar" với tùy chọn classpath bổ sung

MyProgram.jar 
libs/ 

Vì vậy, khi tôi cố gắng để chạy chương trình của tôi bây giờ tôi nhận được lỗi sau:

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) 

Tại sao điều này xảy ra?

Trả lời

100

Bạn sử dụng một trong hai -jarhoặc-cp, bạn không thể kết hợp cả hai. Nếu bạn muốn đặt các JAR bổ sung trên classpath thì bạn nên đặt chúng trong biểu thức JAR chính và sau đó sử dụng java -jar hoặc bạn đặt classpath đầy đủ (bao gồm JAR chính và các phụ thuộc của nó) trong -cp và đặt tên lớp chính một cách rõ ràng trên dòng lệnh

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

(tôi đang sử dụng cú pháp dir/* mà nói với lệnh java để thêm tất cả .jar tập tin từ một thư mục cụ thể để classpath. Lưu ý rằng * phải được bảo vệ từ việc mở rộng bằng vỏ, đó là tại sao tôi đã sử dụng dấu nháy đơn.)

Bạn đề cập đến điều đó yo bạn đang sử dụng Ant như vậy cho phương pháp biểu hiện thay thế, bạn có thể sử dụng tác vụ <manifestclasspath> của kiến ​​sau khi sao chép các phụ thuộc nhưng trước khi tạo 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> 

Với điều này tại chỗ, java -jar MyProgram.jar sẽ làm việc một cách chính xác, và sẽ bao gồm tất cả các libs file JAR trên classpath là tốt.

+0

Thêm vào trên, Hoặc nghĩ về việc thêm các mục jar cần thiết trong file MANIFEST.MF . –

+0

@HimanshuBhardwaj thực sự, tôi đã thêm một ví dụ về làm thế nào để làm điều đó bằng cách sử dụng '' –

+0

Yep, Chỉ cần nhìn thấy bản cập nhật vài giây trở lại. –

7

Khi tùy chọn -jar được sử dụng tùy chọn -cp được bỏ qua. Cách duy nhất để đặt classpath là sử dụng tệp kê khai trong jar.

Việc sử dụng tùy chọn -cp dễ dàng hơn, thêm tệp jar của bạn vào đó, sau đó gọi rõ ràng lớp chính.

Ngoài ra, giả sử thư mục/home/user/java/MyProgram/jar/libs chứa các tệp jar (ngược lại với tệp lớp), điều này sẽ không hoạt động. Bạn không thể chỉ định một thư mục của tệp jar nhưng phải chỉ định từng tệp jar riêng lẻ trong classpath (thật đáng để viết một kịch bản lệnh shell đơn giản để làm điều này cho bạn nếu có một số lượng lớn các jars).

0

Đó là một chút khó khăn. Kịch bản sau đây là một nỗ lực để có được classpath từ tệp kê khai của jar và sau đó cho phép thêm các mục nhập classpath thừa. Tôi đã có kết quả hỗn hợp với điều này nhưng muốn chia sẻ kịch bản tuy nhiên do đó, nó có thể được thực hiện đầy đủ chức năng ở đây.

Các kịch bản có hai tên

  • showmanifest
  • calljar

bởi hardlinking file hai cùng với

ln calljar showmanifest 

với calljar -h bạn có thể xem cách sử dụng .

#!/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="[email protected]"; 
    #echo "mainclass=${mainclass}" 
    #echo "classpath=${classpath}" 

    #echo calljar "${dir}" "${jar}" "${classpath}" "$pattern" "$arguments" 
    calljar "$dir" "$jar" "$classpath" "$pattern" "$arguments" 
    ;; 
esac 
0

Để kiểm tra nhanh chóng, một lần một ứng dụng, bạn có thể chỉ cần liên kết tệp phụ thuộc JAR cần thiết vào thư mục chứa tệp JAR ứng dụng chính.

Ví dụ (đối với một ứng dụng app.jar trong đó sử dụng thư viện Eclipse SWT, mà trong trường hợp của tôi đã được cài đặt trong /usr/share/java):

$ ln -s /usr/share/java/swt.jar . 
$ java -jar app.jar 
Các vấn đề liên quan