2012-03-26 10 views
7

Spojrzałem na this question, ale to naprawdę nie rozwiązało mojego problemu, więc pomyślałem, że opublikuję nowy.jak utworzyć pakietowy, działający jar, używając Ant

Potrzebuję utworzyć działający słoik (można go uruchomić po prostu klikając dwukrotnie) za pomocą Ant. Mam następujący kod java i plik build.xml, który kompiluje kod po prostu dobrze i tworzy plik jar, ale gdy spróbuję uruchomić jar przez podwójne kliknięcie, pojawia się komunikat "Nie można znaleźć głównej klasy: HttpController. Jawa."

Mam podejrzenie, że mój problem ma związek z ładowaniem zewnętrznego Apache Http.jar, ponieważ udało mi się zbudować i uruchomić słoik dla projektu, który jest identyczny, z tym że nie odnosi się do żadnych zewnętrznych słoików.

Oto mój kod:

HttpController.java:

package pack; 

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 

import org.apache.http.HttpEntity; 
import org.apache.http.HttpHost; 
import org.apache.http.HttpMessage; 
import org.apache.http.HttpResponse; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.impl.client.DefaultHttpClient; 

public class HttpController { 
     public static void main(String[] args) { 

     DefaultHttpClient client = new DefaultHttpClient(); 
     HttpHost httphost = new HttpHost("localhost", 80); 

     try { 

      HttpMessage req = new HttpGet("/test.html"); 
      HttpResponse resp = client.execute(httphost, (HttpGet) req); 
      HttpEntity entity = resp.getEntity(); 

      BufferedReader in = new BufferedReader(new InputStreamReader(
        entity.getContent())); 

      String line = null; 
      while ((line = in.readLine()) != null) { 
       System.out.println(line); 
      } 

     } catch (ClientProtocolException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } finally { 
      // shutdown the connection 
      client.getConnectionManager().shutdown(); 
     } 
    } 
} 

build.xml:

<?xml version="1.0" encoding="ISO-8859-1"?> 
    <project name="Test" basedir="." default="jar"> 
    <property name="source.dir"  value="src"/> 
    <property name="lib.dir"  value="lib"/> 
    <property name="class.dir"  value="bin"/> 
    <property name="jar.dir"  value="dist"/> 
    <property name="main-class"  value="pack.HttpController"/> 

    <path id="libraries.path">  
     <fileset dir="${lib.dir}"> 
      <include name="*.jar"/> 
     </fileset> 
    </path> 

    <target name="clean" description="delete old files"> 
     <delete dir="${class.dir}"/> 
     <delete dir="${jar.dir}"/> 
    </target> 

    <target name="compile" description="build class files" depends="clean"> 
     <mkdir dir="${class.dir}"/> 
     <javac srcdir="${source.dir}" destdir="${class.dir}"> 
      <classpath refid="libraries.path"/> 
     </javac> 
    </target> 

    <target name="jar" depends="compile"> 
     <mkdir dir="${jar.dir}"/> 
     <mkdir dir="${jar.dir}/${lib.dir}"/> 
     <copy todir="${jar.dir}/${lib.dir}" flatten="true"> 
      <path refid="libraries.path"/> 
     </copy> 
     <jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${class.dir}"> 
      <manifest> 
       <attribute name="Main-Class" value="${main-class}"/> 
       <attribute name="Class-Path" value="${jar.dir}/${lib.dir}/Apache HTTP.jar"/> 
      </manifest> 
     </jar> 
    </target> 

    <target name="run" depends="jar"> 
     <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/> 
    </target> 
</project> 

MANIFEST.MF:

Manifest-Version: 1.0 
Ant-Version: Apache Ant 1.8.3 
Created-By: 1.6.0_31-b05 (Sun Microsystems Inc.) 
Main-Class: HttpController 
Class-Path: dist/lib 

EDIT plik build.xml został zaktualizowany zgodnie z odpowiedzią Mike'a. Problem nadal nie został rozwiązany. Zamieszczono również treść pliku manifestu, zgodnie z odpowiedzią Danation.

+0

@ see http://one-jar.sourceforge.net/index.php?page=build-tools&file=ant-example. – Jayan

+0

@jayan czy można to zrobić bez zewnętrznych narzędzi? tj. po prostu używając Ant i napisanie własnego pliku build.xml? – ewok

+0

Istnieją pytania/odpowiedzi w SO na temat tworzenia działających słoików za pomocą Eclipse itp. Zobacz ten http://stackoverflow.com/questions/502960/eclipse-how-to-build-an-executable-jar-with-external-jar. Wolę jeden-jar, ponieważ tworzy pojedynczy uruchamiany plik. Intgrating to mrówka powinna zająć 10 minut. Dlaczego więc nie spróbować zobaczyć wyniku? – Jayan

Odpowiedz

0

Spójrz na plik manifestu, najprawdopodobniej jest to problem. Widziałem tylko ten błąd, gdy plik manifestu jest niepoprawny.

Tylko spekulacje, ale myślę, że to stara się uruchomić plik ".java", ponieważ jest to główna klasa, która nie zadziała.

Zobacz samouczek na temat oracle: http://docs.oracle.com/javase/tutorial/deployment/jar/appman.html.

Jeśli to nie pomoże, opublikuj zawartość pliku manifestu, a także strukturę katalogów pliku .jar w oryginalnym pytaniu.

+0

Wiem, że wystąpił problem z plikiem manifestu, ale muszę wiedzieć, jak ponownie skonfigurować plik build.xml, aby mrówka generowała go poprawnie. – ewok

+1

@wok: Opublikuj zawartość pliku manifestu, a także strukturę katalogów pliku .jar w oryginalnym pytaniu. Po zidentyfikowaniu problemu powinieneś wiedzieć, gdzie znajduje się problem w pliku build.xml. – Danation

+0

opublikowane. Zaktualizowałem również plik build.xml na podstawie odpowiedzi Mike'a – ewok

16

Snip ...

mam przerobiony plik build.xml prawidłowo zawierać bibliotek w pliku jar i w manifeście ścieżce klasy. Jestem zakładając, że plik „apache http.jar” jest opakowaniem dla Apache Core i zawiera kilka innych plików jar w nim dla klienta apache itp

build.xml

<?xml version="1.0" encoding="ISO-8859-1"?> 
<project name="Test" basedir="." default="jar"> 
    <property name="source.dir"  value="src"/> 
    <property name="lib.dir"  value="lib"/> 
    <property name="class.dir"  value="bin"/> 
    <property name="jar.dir"  value="dist"/> 
    <property name="jar.file"  value="${jar.dir}/${ant.project.name}.jar"/> 
    <property name="main-class"  value="pack.HttpController"/> 

    <path id="libraries.path">  
     <fileset dir="${lib.dir}"> 
      <include name="*.jar"/> 
     </fileset> 
    </path> 

    <target name="clean" description="delete old files"> 
     <delete dir="${class.dir}"/> 
     <delete dir="${jar.dir}"/> 
    </target> 

    <target name="compile" description="build class files" depends="clean"> 
     <mkdir dir="${class.dir}"/> 
     <javac srcdir="${source.dir}" destdir="${class.dir}"> 
      <classpath refid="libraries.path"/> 
     </javac> 
    </target> 

    <target name="jar" depends="compile"> 
     <mkdir dir="${jar.dir}"/> 
     <mkdir dir="${class.dir}/${lib.dir}"/> 
     <copy todir="${class.dir}/${lib.dir}" flatten="true"> 
      <path refid="libraries.path"/> 
     </copy> 

     <manifestclasspath property="manifest.classpath" jarfile="${jar.file}"> 
      <classpath refid="libraries.path"/> 
     </manifestclasspath> 

     <jar destfile="${jar.file}" basedir="${class.dir}"> 
      <manifest> 
       <attribute name="Main-Class" value="${main-class}"/> 
       <attribute name="Class-Path" value="${manifest.classpath}"/> 
      </manifest> 
     </jar> 
    </target> 

    <target name="run" depends="jar"> 
     <java jar="${jar.dir}/${ant.project.name}.jar" fork="true"/> 
    </target> 

</project> 
+0

Wprowadziłem zmiany zalecane. Kilka rzeczy, które musiałem zmienić (nie ma właściwości '$ {dist}', myślę że chodziło o '$ {jar.dir}'), ale kompilacja nadal zwraca ten sam błąd. – ewok

+0

Należy również uwzględnić układ katalogu pliku jar. Zastanawiam się, czy rt jest zdenerwowany, że twoja klasa jest w domyślnym pakiecie. – Mike

+0

Przeniosłem 'HttpController.java' do pakietu' pack' (src/pack) i dostosowałem plik build.xml, aby to odzwierciedlić, ale wystąpił ten sam błąd. – ewok

4

Twój Class-Path Wpis jest nieprawidłowy, należy określić każdy plik jar indywidualnie, nie można określić katalogu z plikami .jar (tylko katalogi z.Pliki klasa)

Jest to udokumentowane w JAR File specification i wyjaśnił całkiem ładnie w Java tutorial

Jeśli masz dwie biblioteki wymienić FirstLib.jar i SeconLib.jar Twój wpis Class-Path powinien wyglądać następująco:

Class-Path: lib/FirstLib.jar lib/SecondLib.jar 

Edytuj:
Wewnątrz pliku build.xml będzie to wyglądać następująco:

<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${class.dir}"> 
    <manifest> 
     <attribute name="Main-Class" value="${main-class}"/> 
     <attribute name="Class-Path" value="${lib.dir}/FirstLib.jar ${lib.dir}/SecondLib.jar"/> 
    </manifest> 
</jar> 
+0

Edytowałem plik build.xml, aby to odzwierciedlić, ale nadal otrzymuję błąd braku głównej klasy. Niezależnie od reasono, nie rozpoznaję głównej klasy, którą zdefiniowałem. – ewok

+0

Czy twoja główna klasa naprawdę nie ma paczki? Ponieważ to definiuje 'Main-Class: HttpController'. –

+0

Zaktualizuję powyższy kod. początkowo nie miał pakietu, ale dodałem do niego pakiet i wciąż napotykam ten sam problem – ewok

1

Jest to bardziej ogólne rozwiązanie do tworzenia plików wykonywalnych jar ale jest to kod używam:

<?xml version="1.0" encoding="UTF-8"?> 

<!-- 
    Any words or attribute values which are capitalized and separated by 
    underscores are places where you add the data. 

    Example: PROJECT_NAME, enter your project name 
--> 

<project name="PROJECT_NAME" default="jar" basedir="."> 
    <!-- source code package --> 
    <property name="src" value="SOURCE_CODE_FOLDER"/> 

    <!-- classes folder (will be deleted) --> 
    <property name="cls" value="classes"/> 

    <!-- the directory of the jar file --> 
    <property name="jar.dir" value="JAR_FILE_DIRECTORY"/> 

    <!-- the jar file itself --> 
    <property name="jar.file" value="${jar.dir}/${ant.project.name}-launch.jar"/> 

    <!-- the fully qualified name of the main class --> 
    <property name="main" value="PATH.TO.MAIN_CLASS"/> 

    <!-- initialization --> 
    <target name="-init"> 

     <!-- the class folder* --> 
     <mkdir dir="${cls}"/> 

     <!-- the jar directory --> 
     <mkdir dir="${jar.dir}"/> 
    </target> 

    <!-- compiling of files --> 
    <target name="-post-init-comp" depends="-init"> 

     <!-- 
      turn all of the source java classes into class files 
      located in the directory we made* 
     --> 
     <javac srcdir="${src}" destdir="${cls}"/> 
    </target> 

    <!-- creation of the jar file --> 
    <target name="jar" depends="-post-init-comp"> 

     <!-- make the executable jar --> 
     <jar destfile="${jar.file}" basedir="${cls}"> 
      <manifest> 

       <attribute name="Manifest-Version" value="1.0"/> 
       <attribute name="Ant-Version" value="Apache Ant 1.8.3"/> 

       <attribute name="Main-Class" value="${main}"/> 

       <!-- 
        for some reason, this is needed for me in order 
        to have the jar function right 
       --> 
       <attribute name="Class-Path" value="${main}"/> 

       <!-- Any other mainfest data is added here --> 

      </manifest> 
     </jar> 

     <!-- remove the class folder --> 
     <delete dir="${cls}"/> 
    </target> 
</project> 

Użyłem tej struktury, aby różne wykonywalne pliki jar, plus to jest prostsze niż to, co miałeś :-)

Wszystkie dane umieszczone w znacznikach manifestu pod znacznikami jar staną się automatycznie generowanym plikiem manifestu z podanymi danymi.

Powiązane problemy