เรียก“ java -jar MyFile.jar” พร้อมตัวเลือก classpath เพิ่มเติม


93

ฉันสร้างไฟล์ jar ที่มีเนื้อหาที่รวบรวมไว้ทั้งหมด นอกจากนี้สคริปต์สร้างมดของฉันยังคัดลอก 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 เพิ่มเติมใน classpath คุณควรใส่ไว้ในรายการหลักของ JAR จากนั้นใช้java -jarหรือใส่คลาสพา ธ แบบเต็ม (รวมถึง JAR หลักและการอ้างอิง) -cpและตั้งชื่อคลาสหลักอย่างชัดเจนบนบรรทัดคำสั่ง

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

(ฉันใช้dir/*ไวยากรณ์ที่บอกjavaคำสั่งให้เพิ่ม.jarไฟล์ทั้งหมดจากไดเร็กทอรีเฉพาะไปยัง classpath โปรดทราบว่า*ต้องได้รับการป้องกันจากการขยายโดยเชลล์ซึ่งเป็นสาเหตุที่ฉันใช้เครื่องหมายคำพูดเดี่ยว)

คุณระบุว่าคุณกำลังใช้ 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 ทั้งหมดบน classpath ด้วย


เพิ่มไปข้างบนหรือนึกถึงการเพิ่มรายการ jar ที่ต้องการในไฟล์ MANIFEST.MF
Himanshu Bhardwaj

@HimanshuBhardwaj แน่นอนฉันได้เพิ่มตัวอย่างวิธีการใช้งาน<manifestclasspath>
Ian Roberts

เกิดอะไรขึ้นกับ ':' ใน 'MyProgram.jar: libs / *' นี่คือตัวแยกหรือไม่
Gobliins

@Gobliins โคลอนเป็นตัวคั่นระหว่างรายการในพา ธ ภายใต้ระบบปฏิบัติการ Linux และ Mac ใน Windows คุณจะใช้เครื่องหมายอัฒภาค ( ;) แทนเนื่องจากเครื่องหมายทวิภาคบน Windows ใช้สำหรับอักษรระบุไดรฟ์ OP ใช้เครื่องหมายโคลอนและเครื่องหมายทับในคำถามโดยบอกว่าใช้บน Linux หรือ Mac
Ian Roberts

5
หากอ็อพชันไม่รวมกันบรรทัดคำสั่งควรพิมพ์คำเตือนเมื่อใช้ทั้งสองอย่าง ใครมีเวลาสำหรับเรื่องไม่สำคัญนี้!
JJS

22

เมื่อ-jarใช้-cpตัวเลือกตัวเลือกนี้จะถูกละเว้น วิธีเดียวในการตั้งค่า classpath คือการใช้ไฟล์ manifest ใน jar

ง่ายกว่าเพียงแค่ใช้-cpตัวเลือกเพิ่มไฟล์ jar ของคุณลงในไฟล์นั้นจากนั้นเรียกคลาสหลักอย่างชัดเจน

นอกจากนี้สมมติว่า/home/user/java/MyProgram/jar/libsโฟลเดอร์มีไฟล์ jar (ตรงข้ามกับไฟล์คลาส) สิ่งนี้จะไม่ทำงาน คุณไม่สามารถระบุโฟลเดอร์ของไฟล์ jar ได้ แต่ต้องระบุไฟล์ jar แต่ละไฟล์ทีละไฟล์ใน classpath (ควรเขียนเชลล์สคริปต์อย่างง่ายเพื่อทำสิ่งนี้ให้คุณหากมี jar จำนวนมาก)


0

เป็นเรื่องที่ยุ่งยากเล็กน้อย สคริปต์ต่อไปนี้เป็นความพยายามในการรับ classpath จากรายการของ jar จากนั้นอนุญาตให้เพิ่มรายการ classpath เพิ่มเติม ฉันมีผลลัพธ์ที่หลากหลายกับสิ่งนี้ แต่ต้องการแบ่งปันสคริปต์อย่างไรก็ตามมันอาจจะทำให้ใช้งานได้อย่างสมบูรณ์ที่นี่

สคริปต์มีสองชื่อ

  • การแสดง
  • 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.