2016-05-18 12 views
1

Dies ist als Antwort auf die near-universally accepted answer zu einem old question. Da die Antwort ziemlich alt ist (2009) und da es für mich nicht funktioniert, dachte ich, ich würde fragen, ob jemand weiß warum.Das Lesen meines eigenen Jar's Manifest Take 2

Mein Anwendungsfall ist die Entwicklung eines Gravel Plugins für den internen Gebrauch. Wann immer das Plugin angewendet wird, würde ich gerne in der Lage sein zu drucken, welche Version meines Plugins verwendet wird. Also schreibe ich die Version in das Manifest des Plugins, wenn das Plugin erstellt wird, und versuche, es aus dem Manifest zu lesen, wenn das Plugin angewendet wird. Dabei verwende ich die Technik in der verknüpften Antwort.

Ich schrieb einige Code in die Zeilen der Antwort, aber es funktioniert nicht. Ich habe eine Reihe von Debugging-Code, und ich kann sehen, dass der Code zuerst das Manifest vom JDK bereitgestellt findet sich:

Manifest-Version: 1.0 
Created-By: 1.7.0_07 (Oracle Corporation) 

Dann findet es mein Manifest, das eine die ich suche, aber wirft ein FileNotFoundException:

java.io.FileNotFoundException: Der JAR-Eintrag META-INF/MANIFEST.MF wurde nicht in {Pfad zu meinem Plugin-Jar in meinem lokalen Maven-Repository} gefunden. Wie konnte

 Enumeration<URL> resources = getClass().getClassLoader() 
       .getResources("META-INF/MANIFEST.MF"); 

das Manifest finden und dann eine FileNotFoundException werfen, wenn sie mit ihm zu lesen versuchen:

Manifest manifest = new Manifest(resources.nextElement().openStream()); 

Das ist die Linie, wo die Ausnahme ausgelöst wird.

Kann jemand dieses seltsame Verhalten erklären oder sich eine andere, vielleicht neuere Art vorstellen, das Manifest zu lesen?

Dies läuft übrigens unter Eclipse, in Windows. Habe es noch nicht auf Linux versucht, wo es eigentlich funktionieren könnte, aber ich würde es gerne in beiden Fällen nutzen.

+1

Welche Attribute des Manifests möchten Sie lesen? Viele versionsbezogene Manifestattribute sind als Methoden der Klasse [java.lang.Package] (http://docs.oracle.com/javase/8/docs/api/java/lang/Package.html) verfügbar. – VGR

+0

Ja, ich habe gerade das Gleiche gefunden, danke. Siehe meine gerade gepostete Antwort. –

Antwort

2

Wenn es nach mir ginge, würde ich eine Java-Datei bei der Erstellung enthält die Version generiert:

Beispiel: Legen Sie die folgende Datei in src/template/java/com/foo/MyPluginProperties.java

package com.foo; 
public class MyPluginProperties { 
    public static String getVersion() { 
     return "@[email protected]"; 
    } 
} 

Dann in build.gradle

def generatedJava = file("$buildDir/generated/java") 
task generateSource(type:Copy) { 
    def tokens = [version: project.version] 

    // configure task inputs for gradle's up-to-date checks 
    inputs.property "tokens", tokens 
    from "src/template/java" 
    filter(ReplaceTokens, tokens: tokens) 
    into generatedJava 
} 

// wire the task into the gradle DAG 
compileJava.dependsOn generateSource 

// add the generated directory to the main source set so it's compiled 
sourceSets.main.java { 
    srcDir generatedJava 
} 

Dann könnten Sie in Ihrem Plugin Folgendes aufrufen:

com.foo.MyPluginProperties.getVersion() 
+0

Danke. Dies ist nützlich für meinen speziellen Anwendungsfall. Ich möchte immer noch wissen, warum die FileNotFoundException in meiner ursprünglichen Methode auftritt. –

+0

Keine Ahnung, vielleicht schließen Sie den vorherigen Eingang nicht? Tapestry IOC macht etwas ähnliches [hier] (https://github.com/apache/tapestry-5/blob/1362c6d2c42082196af54607b3c370f8c9ecfbe7/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/IOCUtilities.java#L76) –

+0

Das ist es nicht. Ich dachte darüber nach und stellte sicher, dass ich den vorherigen Eingangsstrom geschlossen hatte und das half nichts. –

1

Anstatt zu versuchen, Manifest zu lesen, mit den seltsamen IO-Problemen (, die ich immer noch gerne verstehen würde), können wir nutzen, was der Java Class Loader bereits im java.lang.Package bietet. Es gibt den private Package(String name, Manifest man, URL url, ClassLoader loader)-Konstruktor, der aufgerufen wird, wenn ein Paket aus einem Jar geladen wird. Er liest das Manifest der Standardattribute und speichert sie in Paketelementvariablen:

private final String pkgName; 
private final String specTitle; 
private final String specVersion; 
private final String specVendor; 
private final String implTitle; 
private final String implVersion; 
private final String implVendor; 

Diese manifestieren Einträge müssen die richtigen Tasten zum Beispiel „Implementation-Version“, etc., die in java.util.jar.Attributes.Name

Mit dem Manifest gebaut nach diesen Normen zu finden sind, ist es möglich, diese Werte zu erhalten ohne andere lesen zu tun.Hat Tipp zu https://stackoverflow.com/a/23280647/811299