2008-09-17 8 views
20

मैंने इसे समझने की कोशिश करने में बहुत अधिक समय बिताया है। यह सबसे आसान बात होनी चाहिए और जार में जावा अनुप्रयोगों को वितरित करने वाले प्रत्येक व्यक्ति को इससे निपटना होगा।आप MANIFEST.MF कैसे बनाते हैं जो उत्पादन में एक जार से परीक्षण और चलते समय उपलब्ध होता है?

मैं बस अपने जावा ऐप में वर्जनिंग जोड़ने का उचित तरीका जानना चाहता हूं ताकि जब मैं परीक्षण कर रहा हूं, तो मैं संस्करण की जानकारी तक पहुंच सकता हूं, उदा। ग्रहण और में एक जार से चलने में डीबगिंग।

<target name="jar" depends = "compile"> 
    <property name="version.num" value="1.0.0"/> 
    <buildnumber file="build.num"/> 
    <tstamp> 
     <format property="TODAY" pattern="yyyy-MM-dd HH:mm:ss" /> 
    </tstamp> 

    <manifest file="${build}/META-INF/MANIFEST.MF"> 
     <attribute name="Built-By" value="${user.name}" /> 
     <attribute name="Built-Date" value="${TODAY}" />     
     <attribute name="Implementation-Title" value="MyApp" /> 
     <attribute name="Implementation-Vendor" value="MyCompany" />     
     <attribute name="Implementation-Version" value="${version.num}-b${build.number}"/>        
    </manifest> 

    <jar destfile="${build}/myapp.jar" basedir="${build}" excludes="*.jar" />     
</target> 

यह /META-INF/MANIFEST.MF बनाता है और मैं मान जब मैं thusly ग्रहण में डीबगिंग कर रहा हूँ पढ़ सकते हैं::

public MyClass() 
{ 
    try 
    {       
     InputStream stream = getClass().getResourceAsStream("/META-INF/MANIFEST.MF"); 
     Manifest manifest = new Manifest(stream);    

     Attributes attributes = manifest.getMainAttributes(); 

     String implementationTitle = attributes.getValue("Implementation-Title"); 
     String implementationVersion = attributes.getValue("Implementation-Version"); 
     String builtDate = attributes.getValue("Built-Date"); 
     String builtBy = attributes.getValue("Built-By"); 
    } 
    catch (IOException e) 
    {    
     logger.error("Couldn't read manifest."); 
    }   

यहाँ क्या मैं अपने build.xml में है

}

लेकिन, जब मैं जार फ़ाइल बनाने, यह एक जार के प्रकट लोड करता है (शायद पहले जार आवेदन द्वारा लोड - मेरे मामले, activation.jar में)।

इसके अलावा, निम्न कोड काम नहीं करता है हालांकि सभी उचित मान मैनिफेस्ट फ़ाइल में हैं।

Package thisPackage = getClass().getPackage(); 
    String implementationVersion = thisPackage.getImplementationVersion(); 

कोई विचार?

उत्तर

0

बस मैनिफेस्ट का उपयोग न करें। जैसे संस्करण = @ संस्करण @

और वहाँ एक ही कार्य में आप आप foo.properties.original copu की एक प्रति क्या कर सकते हैं jaring रहे हैं और फिर

0
एक सामग्री के साथ एक foo.properties.original फ़ाइल बनाएँ,

मैं आमतौर पर एक संस्करण फ़ाइल का उपयोग भी करूंगा। मैं प्रति जार एक फाइल बनाउंगा क्योंकि प्रत्येक जार का अपना संस्करण हो सकता है।

1

यदि आप कक्षाओं को लोड करने के लिए उपयोग किए जाने वाले समान वर्ग लोडर का उपयोग करते हैं तो आप एक जार के भीतर मेनिफेस्ट (या किसी अन्य) फ़ाइल तक पहुंच सकते हैं।

this.getClass().getClassLoader().getResourceAsStream(...) ; 

आप निम्नलिखित मल्टी-थ्रेडेड उपयोग कर रहे हैं:

Thread.currentThread().getContextClassLoader().getResourceAsStream(...) ; 

यह भी जार के अंदर एक डिफ़ॉल्ट विन्यास फाइल सहित के लिए एक बहुत उपयोगी तकनीक है।

2

आप इस का उपयोग करना चाहते हैं:

Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF"); 

आप यह पता लगाने की जो जार प्रकट से अगर और फिर getInputStream() के माध्यम से URL पढ़ें प्रकट पार्स करने के लिए करने के लिए यूआरएल पार्स कर सकते हैं।

1

यहाँ मैं क्या पाया है कि काम करता है:

packageVersion.java:

package com.company.division.project.packageversion; 

import java.io.IOException; 
import java.io.InputStream; 
import java.util.jar.Attributes; 
import java.util.jar.Manifest; 

public class packageVersion 
{ 
    void printVersion() 
    { 
     try 
     {   
      InputStream stream = getClass().getResourceAsStream("/META-INF/MANIFEST.MF"); 

      if (stream == null) 
      { 
       System.out.println("Couldn't find manifest."); 
       System.exit(0); 
      } 

      Manifest manifest = new Manifest(stream); 

      Attributes attributes = manifest.getMainAttributes(); 

      String impTitle = attributes.getValue("Implementation-Title"); 
      String impVersion = attributes.getValue("Implementation-Version"); 
      String impBuildDate = attributes.getValue("Built-Date"); 
      String impBuiltBy = attributes.getValue("Built-By"); 

      if (impTitle != null) 
      { 
       System.out.println("Implementation-Title: " + impTitle); 
      }    
      if (impVersion != null) 
      { 
       System.out.println("Implementation-Version: " + impVersion); 
      } 
      if (impBuildDate != null) 
      { 
       System.out.println("Built-Date: " + impBuildDate); 
      } 
      if (impBuiltBy != null) 
      { 
       System.out.println("Built-By: " + impBuiltBy); 
      } 

      System.exit(0); 
     } 
     catch (IOException e) 
     {    
      System.out.println("Couldn't read manifest."); 
     }   
    } 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) 
    { 
     packageVersion version = new packageVersion(); 
     version.printVersion();   
    } 

} 

यहाँ मिलान का निर्माण है।xml:

<project name="packageVersion" default="run" basedir="."> 

    <property name="src" location="src"/> 
    <property name="build" location="bin"/> 
    <property name="dist" location="dist"/> 

    <target name="init"> 
     <tstamp> 
      <format property="TIMESTAMP" pattern="yyyy-MM-dd HH:mm:ss" /> 
     </tstamp> 
     <mkdir dir="${build}"/> 
     <mkdir dir="${build}/META-INF"/> 
    </target> 

    <target name="compile" depends="init"> 
     <javac debug="on" srcdir="${src}" destdir="${build}"/> 
    </target> 

    <target name="dist" depends = "compile">   
     <mkdir dir="${dist}"/>  
     <property name="version.num" value="1.0.0"/> 
     <buildnumber file="build.num"/> 
     <manifest file="${build}/META-INF/MANIFEST.MF"> 
      <attribute name="Built-By" value="${user.name}" /> 
      <attribute name="Built-Date" value="${TIMESTAMP}" />         
      <attribute name="Implementation-Vendor" value="Company" /> 
      <attribute name="Implementation-Title" value="PackageVersion" /> 
      <attribute name="Implementation-Version" value="${version.num} (b${build.number})"/> 
      <section name="com/company/division/project/packageversion"> 
       <attribute name="Sealed" value="false"/> 
      </section>   
     </manifest>  
     <jar destfile="${dist}/packageversion-${version.num}.jar" basedir="${build}" manifest="${build}/META-INF/MANIFEST.MF"/>     
    </target> 

    <target name="clean"> 
     <delete dir="${build}"/> 
     <delete dir="${dist}"/> 
    </target> 

    <target name="run" depends="dist">  
     <java classname="com.company.division.project.packageversion.packageVersion"> 
      <arg value="-h"/> 
      <classpath> 
       <pathelement location="${dist}/packageversion-${version.num}.jar"/> 
       <pathelement path="${java.class.path}"/> 
      </classpath> 
     </java> 
    </target> 

</project> 
+0

किसी भी तीसरे पक्ष के पुस्तकालयों का उपयोग करता है एक वास्तविक दुनिया आवेदन में, यह निहायत गलत लौटने की संभावना है प्रकट। –

+0

कक्षा का नाम अपरकेस में शुरू होना चाहिए। यह पैकेज संस्करण के बजाय पैकेजवर्सन होना चाहिए। – Carlos

1

ClassLoader.getResource(String) यह classpath, जो कुछ अन्य JAR फ़ाइल के लिए प्रकट हो सकता है पर पाता है पहले प्रकट लोड होगा। इस प्रकार, आप या तो enumerate all the manifests को अपने इच्छित व्यक्ति को ढूंढने या किसी अन्य तंत्र का उपयोग करने के लिए कर सकते हैं, जैसे एक अद्वितीय नाम वाले गुण फ़ाइल।

+0

आप सही हैं कि getResource() अक्सर गलत प्रकट होता है; मैं इसका अनुभव कर रहा हूं; मैंने क्लासलोडर.getResources() के सभी लिंक की गणना करने के लिए आपके लिंक की कोशिश की, लेकिन प्राप्त करें स्रोत ("/ मेटा-आईएनएफ/मैनिफ़ेस्ट.एमएफ") कुछ भी नहीं देता है, और प्राप्त करें स्रोत (") कुछ भी नहीं बल्कि उपयोगी से कम लौटाता है। मुझे संदेह है कि मैं गलत वर्ग लोडर का उपयोग कर रहा हूं, लेकिन फिर "सभी प्रकटताओं का आकलन करें" सभी क्लासलोडर्स की गणना करें "! – metamatt

1

मुझे मैकडॉवेल द्वारा सच होने की टिप्पणी मिली है - जो मैनिफ़ेस्ट.एमएफ फ़ाइल उठाई जाती है, क्लासपाथ पर निर्भर करती है और शायद वह नहीं चाहता था। मैं का उपयोग इस

String cp = PCAS.class.getResource(PCAS.class.getSimpleName() + ".class").toString(); 
cp = cp.substring(0, cp.indexOf(PCAS.class.getPackage().getName())) 
       + "META-INF/MANIFEST.MF"; 
Manifest mf = new Manifest((new URL(cp)).openStream()); 

जो मैं से link text

+0

यह लगभग मेरे लिए काम करता है, यद्यपि यह लिंक कहां से मिला है, अब टूटा हुआ है। मैं "लगभग" कहता हूं क्योंकि Class.getPackage() एक डॉट से अलग नाम (org.foo.bar) देता है, और Class.getSimpleName() एक स्लैश-पृथक नाम (org/foo/bar) देता है। इस वजह से, मुझे गिब्स के उत्तर पसंद हैं जो कक्षा यूआरएल को पार्स करने से बचाता है। – metamatt

10

अनुकूलित आप वर्ग यूआरएल (जो भंगुर हो सकता है) को पार्स करने के बिना एक मनमाना जार में एक मनमाना वर्ग के लिए प्रकट हो सकता है। बस एक संसाधन का पता लगाएं जिसे आप जानते हैं कि जार में है, और फिर कनेक्शन को JarURLConnection में डालें।

यदि आप एक जार में कक्षा को बंडल नहीं करते हैं तो कोड को काम करना चाहते हैं, तो यूआरएल कनेक्शन के प्रकार पर जांच का उदाहरण जोड़ें। एक अनपॅक क्लास पदानुक्रम में कक्षाएं JarUrlConnection के बजाय एक आंतरिक सूर्य FileURLConnection लौटाएंगी। फिर आप अन्य उत्तरों में वर्णित इनपुटस्ट्रीम विधियों में से किसी एक का उपयोग करके मैनिफेस्ट लोड कर सकते हैं।

@Test 
public void testManifest() throws IOException { 
    URL res = org.junit.Assert.class.getResource(org.junit.Assert.class.getSimpleName() + ".class"); 
    JarURLConnection conn = (JarURLConnection) res.openConnection(); 
    Manifest mf = conn.getManifest(); 
    Attributes atts = mf.getMainAttributes(); 
    for (Object v : atts.values()) { 
     System.out.println(v); 
    } 
} 
+0

अच्छा, धन्यवाद। मैंने यहां सब कुछ करने की कोशिश की, और (वर्तमान में 3) उत्तरों जो स्वीकार करते हैं कि class.getResource() अक्सर गलत मैनिफेस्ट (गलत जार में) पाता है और सही प्रकट करने के लिए एक समाधान प्रदान करता है, मुझे यह सबसे अच्छा लगता है। – metamatt

+0

यदि आप कुछ विशिष्ट उपयोग 'atts.getValue ("विशेषता-नाम") 'या' atts.get (नए विशेषताएँ नाम ("विशेषता-नाम"))', गैर-सामान्य कोड एफटीडब्ल्यू चाहते हैं! – TWiStErRob

0

आप jcabi-manifests कि classpath में खोजने के लिए और सभी MANIFEST.MF फ़ाइलों की पार्स automates उपलब्ध से एक उपयोगिता वर्ग Manifests उपयोग कर सकते हैं। उसके बाद, आप एक एक लाइनर के साथ किसी भी विशेषता पढ़ें:

final String name = Manifests.read("Build-By"); 
final String date = Manifests.read("Build-Date"); 

इसके अलावा, इस बाहर की जाँच: http://www.yegor256.com/2014/07/03/how-to-read-manifest-mf.html

संबंधित मुद्दे