रनवे पर मावेन विरूपण साक्ष्य संस्करण प्राप्त करें


177

मैंने देखा है कि एक Maven विरूपण साक्ष्य के JAR में, project.version विशेषता दो फ़ाइलों में शामिल है:

META-INF/maven/${groupId}/${artifactId}/pom.properties
META-INF/maven/${groupId}/${artifactId}/pom.xml

क्या इस संस्करण को रनटाइम पर पढ़ने का कोई अनुशंसित तरीका है?


जवाबों:


265

किसी भी पुस्तकालय / कक्षा के संस्करण की जानकारी प्राप्त करने के लिए आपको मावेन-विशिष्ट फ़ाइलों तक पहुंचने की आवश्यकता नहीं होनी चाहिए।

आप बस getClass().getPackage().getImplementationVersion()एक .jar-files में संग्रहीत संस्करण जानकारी प्राप्त करने के लिए उपयोग कर सकते हैं MANIFEST.MFसौभाग्य से मावेन काफी चालाक है दुर्भाग्य से मावेन डिफ़ॉल्ट रूप से प्रकट होने के लिए सही जानकारी नहीं लिखता है!

इसके बजाय किसी को इस तरह सेट और करने <archive>के maven-jar-pluginलिए कॉन्फ़िगरेशन तत्व को संशोधित करना होगा:addDefaultImplementationEntriesaddDefaultSpecificationEntriestrue

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>                   
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
</plugin>

आदर्श रूप से इस कॉन्फ़िगरेशन को कंपनी pomया किसी अन्य बेस-पोम में डाला जाना चाहिए ।

<archive>तत्व का विस्तृत प्रलेखन मावेन आर्काइव प्रलेखन में पाया जा सकता है ।


6
दुख की बात है कि हर क्लास लोडर इन संपत्तियों को प्रकट फ़ाइल से लोड नहीं करता है (मुझे याद है कि इस मामले में टॉमकैट के साथ समस्याएं हैं)।
डेवजेनर

@avithan: सच में? मुझे इस दृष्टिकोण के साथ टॉमकैट के साथ कोई समस्या नहीं थी। इसके अलावा, मुझे लगता है कि एक क्लास लोडर जो प्रकट को अनदेखा करता है वह शायद अनुरूप नहीं है।
जोआचिम सॉर

@JoachimSauer ठीक है, मैं गलत था। वर्तमान में ऐसा लगता है कि यह हॉटस्पॉट पर बहुत अच्छा काम करता है, लेकिन OpenJDK पर विश्वसनीय काम नहीं करता है। जब मुझे विस्तृत जानकारी मिलेगी तो मैं वापस रिपोर्ट
करूंगा

@avithan यह मेरे लिए प्रासंगिक है (और मैंने यह नहीं देखा कि आप क्या रिपोर्ट करते हैं) - क्या आपने अभी तक विस्तृत जानकारी प्राप्त की है?
थोरबजोरन रावन एंडरसन

4
यदि यह प्रोजेक्ट एक्लिप्स से चलाया जाता है या "mvan exec: java" का उपयोग करके दुर्भाग्य से यह काम नहीं करता है।
जान

77

एक .warकलाकृति के लिए, ऊपर दिए गए उत्तर का पालन करने के लिए , मैंने पाया कि मुझे इसके maven-war-pluginबजाय समतुल्य विन्यास लागू करना था maven-jar-plugin:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1</version>
    <configuration>
        <archive>                   
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
</plugin>

यह करने के लिए संस्करण जानकारी जोड़ा MANIFEST.MFपरियोजना के दशक में .jar(में शामिल WEB-INF/libकी .war)


3
<आर्काइवक्लास> सत्य </ आर्काइवक्लास> के कारण मेरे मामले में त्रुटि हुई। लेकिन समस्या हल हो गई stackoverflow.com/questions/14934299/…
पॉल वेरेस्ट

10
जब मैं यह कोशिश करता हूं तो मेरा परिणाम हमेशा होता है, nullहालांकि युद्ध फाइलों में MANIFEST.MF में सही जानकारी होती है।
thomas.mc.work

मुझे इसे
maven-

2
<आर्काइवक्लास> सच </ संग्रहक्लास> असंबंधित लगता है
कार्ल किल्डन

1
@ RafaelSimonelli मैंने निकाल दिया है <archiveClasses>true</archiveClasses>- और यह तब से मज़बूती से काम करता है।
thomas.mc.work

28

यहाँ pom.properties से संस्करण प्राप्त करने के लिए एक विधि है, इसे प्रकट से वापस प्राप्त करना

public synchronized String getVersion() {
    String version = null;

    // try to load from maven properties first
    try {
        Properties p = new Properties();
        InputStream is = getClass().getResourceAsStream("/META-INF/maven/com.my.group/my-artefact/pom.properties");
        if (is != null) {
            p.load(is);
            version = p.getProperty("version", "");
        }
    } catch (Exception e) {
        // ignore
    }

    // fallback to using Java API
    if (version == null) {
        Package aPackage = getClass().getPackage();
        if (aPackage != null) {
            version = aPackage.getImplementationVersion();
            if (version == null) {
                version = aPackage.getSpecificationVersion();
            }
        }
    }

    if (version == null) {
        // we could not compute the version so use a blank
        version = "";
    }

    return version;
} 

2
इसे स्टैटिक इनिशियलाइज़र ब्लॉक में रखें।
opyate

1
अच्छी सलाह। ।। हालांकि, अगर आप एक सर्वलेट (या .jsp) में इस का उपयोग कर रहे हो यकीन है कि getServletContext () getClass () getResourceAsStream के बजाय getResourceAsStream उपयोग करने के लिए
सैंडमैन

3
यह केवल तभी काम करता है जब एप्लिकेशन जार से चलाया जाता है। यदि निष्पादन-मावेन-प्लगइन (जैसे नेटबीन्स) से चलाया जाता है, तो संसाधन शून्य है।
बजे लीफ ग्रुएनवोल्ड

यह कोड मेरी मुख्य श्रेणी की चूक का हिस्सा होगा! धन्यवाद!!
वेंडेल

मैंने इसे सीधे आगे और विकल्प बनाए रखने में आसान के लिए विल के जवाब के साथ उपयोग किया।
javydreamercsw

3

मैंने यहां दो मुख्य दृष्टिकोणों पर कुछ समय बिताया और उन्होंने मेरे लिए काम नहीं किया। मैं निर्माण के लिए नेटबीन्स का उपयोग कर रहा हूं, हो सकता है कि वहां अधिक चल रहा हो। मुझे कुछ निर्माणों के साथ मावेन 3 से कुछ त्रुटियां और चेतावनियाँ थीं, लेकिन मुझे लगता है कि वे सही करना आसान था। कोई बड़ाई नहीं।

मुझे DZone पर इस लेख को लागू करने के लिए एक जवाब मिल गया है जो देखने योग्य और सरल लगता है:

मेरे पास पहले से ही एक संसाधन / कॉन्फ़िगरेशन उप-फ़ोल्डर है, और मैंने अपनी फ़ाइल का नाम दिया है: app.properties, बेहतर सामान को प्रतिबिंबित करने के लिए जो हम वहां रख सकते हैं (जैसे एक समर्थन URL, आदि)।

एकमात्र चेतावनी यह है कि Netbeans एक चेतावनी देता है कि IDE को फ़िल्टर करने की आवश्यकता है। निश्चित नहीं है कि कहां / कैसे। इस बिंदु पर इसका कोई प्रभाव नहीं है। शायद इसके लिए कोई काम हो, अगर मुझे उस पुल को पार करने की आवश्यकता है। शुभकामनाएँ।


3

मैं maven-assembly-pluginअपने मावेन पैकेजिंग के लिए उपयोग कर रहा हूं । जोआचिम सौरे के जवाब में अपाचे मावेन अभिलेखागार का उपयोग भी काम कर सकता है:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution .../>
    </executions>
</plugin>

क्योंकि अभिलेखीय मावेन साझा घटकों में से एक है , इसका उपयोग कई मावेन बिल्डिंग प्लगइन्स द्वारा किया जा सकता है, जो दो या दो से अधिक प्लगइन्स के archiveअंदर कॉन्फ़िगरेशन सहित, अगर संघर्ष भी हो सकता है।


2

इसे एक्लिप्स में चलाने के लिए, साथ ही साथ मावेन बिल्ड में, आपको अन्य उत्तरों में वर्णित के रूप में addDefaultImplementationEntriesऔर addDefaultSpecificationEntriesपोम प्रविष्टियों को जोड़ना चाहिए , फिर निम्नलिखित कोड का उपयोग करें:

public synchronized static final String getVersion() {
    // Try to get version number from pom.xml (available in Eclipse)
    try {
        String className = getClass().getName();
        String classfileName = "/" + className.replace('.', '/') + ".class";
        URL classfileResource = getClass().getResource(classfileName);
        if (classfileResource != null) {
            Path absolutePackagePath = Paths.get(classfileResource.toURI())
                    .getParent();
            int packagePathSegments = className.length()
                    - className.replace(".", "").length();
            // Remove package segments from path, plus two more levels
            // for "target/classes", which is the standard location for
            // classes in Eclipse.
            Path path = absolutePackagePath;
            for (int i = 0, segmentsToRemove = packagePathSegments + 2;
                    i < segmentsToRemove; i++) {
                path = path.getParent();
            }
            Path pom = path.resolve("pom.xml");
            try (InputStream is = Files.newInputStream(pom)) {
                Document doc = DocumentBuilderFactory.newInstance()
                        .newDocumentBuilder().parse(is);
                doc.getDocumentElement().normalize();
                String version = (String) XPathFactory.newInstance()
                        .newXPath().compile("/project/version")
                        .evaluate(doc, XPathConstants.STRING);
                if (version != null) {
                    version = version.trim();
                    if (!version.isEmpty()) {
                        return version;
                    }
                }
            }
        }
    } catch (Exception e) {
        // Ignore
    }

    // Try to get version number from maven properties in jar's META-INF
    try (InputStream is = getClass()
        .getResourceAsStream("/META-INF/maven/" + MAVEN_PACKAGE + "/"
                + MAVEN_ARTIFACT + "/pom.properties")) {
        if (is != null) {
            Properties p = new Properties();
            p.load(is);
            String version = p.getProperty("version", "").trim();
            if (!version.isEmpty()) {
                return version;
            }
        }
    } catch (Exception e) {
        // Ignore
    }

    // Fallback to using Java API to get version from MANIFEST.MF
    String version = null;
    Package pkg = getClass().getPackage();
    if (pkg != null) {
        version = pkg.getImplementationVersion();
        if (version == null) {
            version = pkg.getSpecificationVersion();
        }
    }
    version = version == null ? "" : version.trim();
    return version.isEmpty() ? "unknown" : version;
}

यदि आपका जावा बिल्ड "टार्गेट / क्लासेस" के अलावा कहीं और टारगेट क्लासेस लगाता है, तो आपको सेगमेंटट्रीमोव का मान समायोजित करने की आवश्यकता हो सकती है।


तुम्हें पता है अगर यह यूनिट परीक्षणों के लिए है तो आप बस कर सकते हैं System.getProperty("user.dir")/pom.xml। मुझे पूरा यकीन है कि यह अन्य चीजों के साथ-साथ WTP के लिए भी नहीं होगा।
एडम जेंट

यह तभी काम करेगा जब आपका प्रोजेक्ट किसी डायरेक्टरी में हो - अगर आप जारफाइल्स में आधारित प्रोजेक्ट चला रहे हैं, तो आपका समाधान काम नहीं करेगा। आप उपयोग करने की आवश्यकता .getResource()है या .getResourceAsStream()
ल्यूक हचिसन

हाँ मैं मान रहा था कि आप पहले ही जार (ala getResource) की जाँच कर चुके हैं। सबसे पहले आप getResource से जांच करें कि यदि वह विफल रहता है, तो प्रोजेक्ट अभी तक जार में नहीं बनाया गया है, जिसका अर्थ है कि आप या तो इसे ग्रहण या मावेन से चला रहे हैं, जिसका अर्थ है 'System.getProperty ("user.dir") / pom .xml । एकमात्र समस्या यह है कि यह pom फ़ाइल सही प्रभावी pom नहीं है (जो कि कुछ गुणों का विस्तार नहीं किया जाएगा) अभी तक है और न ही आप जिस तरह से ग्रहण कर रहे हैं वह है।
एडम जेंट

1

मेरे स्प्रिंग बूट एप्लिकेशन पर, स्वीकृत उत्तर से समाधान तब तक काम किया जब तक कि मैंने हाल ही में संस्करण 12 में अपना jdk अपडेट नहीं किया। अन्य सभी उत्तरों को भी आज़माया और काम करने के लिए इसे प्राप्त नहीं कर सका।

उस बिंदु पर, मैंने एनोटेशन के ठीक बाद अपने स्प्रिंग बूट एप्लिकेशन के पहले वर्ग में नीचे की पंक्ति को जोड़ा @SpringBootApplication

@PropertySources({ 
        @PropertySource("/META-INF/maven/com.my.group/my-artefact/pom.properties")
})

बाद में मैं नीचे का उपयोग गुण फ़ाइल से मूल्य प्राप्त करने के लिए जो भी वर्ग में मैं इसके मूल्य का उपयोग करना चाहता हूं और appVersionमेरे लिए परियोजना संस्करण प्राप्त करता है:

@Value("${version}")
private String appVersion;

आशा है कि किसी की मदद करता है।


एकाधिक pom फ़ाइलों के साथ समान कैसे करें? मैं कई पोम फ़ाइलों से संस्करण लोड करना चाहता हूं।
THM

0

एक सरल समाधान जो मावेन संगत है और किसी के लिए काम करता है (इस प्रकार तीसरे पक्ष) वर्ग:

    private static Optional<String> getVersionFromManifest(Class<?> clazz) {
        try {
            File file = new File(clazz.getProtectionDomain().getCodeSource().getLocation().toURI());
            if (file.isFile()) {
                JarFile jarFile = new JarFile(file);
                Manifest manifest = jarFile.getManifest();
                Attributes attributes = manifest.getMainAttributes();
                final String version = attributes.getValue("Bundle-Version");
                return Optional.of(version);
            }
        } catch (Exception e) {
            // ignore
        }
        return Optional.empty();
    }

-1

जावा प्रोजेक्ट के लिए युद्ध फाइल में EJB के लिए जावा 8 संस्करण। EAP 7.0 पर परीक्षण किया गया।

@Log4j // lombok annotation
@Startup
@Singleton
public class ApplicationLogic {

    public static final String DEVELOPMENT_APPLICATION_NAME = "application";

    public static final String DEVELOPMENT_GROUP_NAME = "com.group";

    private static final String POM_PROPERTIES_LOCATION = "/META-INF/maven/" + DEVELOPMENT_GROUP_NAME + "/" + DEVELOPMENT_APPLICATION_NAME + "/pom.properties";

    // In case no pom.properties file was generated or wrong location is configured, no pom.properties loading is done; otherwise VERSION will be assigned later
    public static String VERSION = "No pom.properties file present in folder " + POM_PROPERTIES_LOCATION;

    private static final String VERSION_ERROR = "Version could not be determinated";

    {    
        Optional.ofNullable(getClass().getResourceAsStream(POM_PROPERTIES_LOCATION)).ifPresent(p -> {

            Properties properties = new Properties();

            try {

                properties.load(p);

                VERSION = properties.getProperty("version", VERSION_ERROR);

            } catch (Exception e) {

                VERSION = VERSION_ERROR;

                log.fatal("Unexpected error occured during loading process of pom.properties file in META-INF folder!");
            }
        });
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.