wake-up-neo.com

Rufen Sie "Java -jar MyFile.jar" mit zusätzlicher Klassenpfadoption auf

Ich habe eine JAR-Datei mit all meinen kompilierten Sachen erstellt. Zusätzlich kopiert mein Ant Build Script die benötigten Bibliotheken in einen Unterordner "libs". Die Struktur sieht folgendermaßen aus:

MyProgram.jar
libs/

Wenn ich versuche, mein Programm jetzt auszuführen, erhalte ich die folgende Fehlermeldung:

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)

Warum passiert das?

74
toom

Sie verwenden entweder-jaroder-cp, Beide können nicht kombiniert werden. Wenn Sie zusätzliche JARs in den Klassenpfad einfügen möchten, sollten Sie diese entweder in das Manifest der Haupt-JAR einfügen und dann Java -jar Verwenden oder den vollständigen Klassenpfad (einschließlich der Haupt-JAR und ihrer Abhängigkeiten) in -cp und benennen Sie die Hauptklasse explizit in der Befehlszeile

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

(Ich verwende die Syntax dir/*, Mit der der Befehl Java angewiesen wird, alle .jar - Dateien aus einem bestimmten Verzeichnis zum Klassenpfad hinzuzufügen. Beachten Sie, dass * muss durch die Shell vor Erweiterung geschützt werden, weshalb ich einfache Anführungszeichen verwendet habe.)

Sie erwähnen, dass Sie Ant verwenden, damit Sie für den alternativen Manifest-Ansatz die Aufgabe <manifestclasspath> Von ant verwenden können after Kopieren der Abhängigkeiten, aber before Erstellen der 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>

Wenn dies aktiviert ist, funktioniert Java -jar MyProgram.jar Ordnungsgemäß und enthält auch alle libs JAR-Dateien im Klassenpfad.

130
Ian Roberts

Wenn der -jar Option wird verwendet die -cp Option wird ignoriert. Die einzige Möglichkeit, den Klassenpfad festzulegen, ist die Verwendung der Manifestdatei in der JAR-Datei.

Es ist einfacher, nur das -cp Option, fügen Sie Ihre JAR-Datei hinzu und rufen Sie dann explizit die Hauptklasse auf.

Unter der Annahme, dass /home/user/Java/MyProgram/jar/libs Ordner enthält JAR-Dateien (im Gegensatz zu Klassendateien) Dies funktioniert nicht. Sie können keinen Ordner für die JAR-Datei angeben, sondern müssen jede JAR-Datei einzeln im Klassenpfad angeben (es lohnt sich, ein einfaches Shell-Skript zu schreiben, um dies für Sie zu tun, wenn eine erhebliche Anzahl von JAR-Dateien vorhanden ist).

17
Jonathan

Für schnelle, einmalige Tests einer App können Sie die erforderlichen JAR-Dateien für Abhängigkeiten einfach mit dem Verzeichnis verknüpfen, das die JAR-Datei für die Haupt-App enthält.

Beispiel (für eine App app.jar, Die die Eclipse-SWT-Bibliothek verwendet, die in meinem Fall in /usr/share/Java Installiert wurde):

$ ln -s /usr/share/Java/swt.jar .
$ Java -jar app.jar
0
ack

Es ist ein bisschen schwierig. Das folgende Skript ist ein Versuch, den Klassenpfad aus dem Manifest der JAR-Datei abzurufen und anschließend zusätzliche Klassenpfadeinträge hinzuzufügen. Ich hatte gemischte Ergebnisse damit, aber ich möchte das Skript trotzdem teilen, damit es hier möglicherweise voll funktionsfähig wird.

Das Skript hat zwei Namen

  • showmanifest
  • calljar

durch festes Verknüpfen der beiden Dateien mit

ln calljar showmanifest

mit calljar -h können Sie die Verwendung sehen.

#!/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
Wolfgang Fahl