V mnohých projektoch by sme chceli mať možnosť zisťovať verzie aktuálneho modulu, a to za behu. Napríklad sa hodí vedieť, že práve bežíme na projekte verzie 0.0.1-SNAPSHOT.
Jedna z veľmi ízy možností využíva polozabudnuté API zo štandardnej Javy, a to najmä triedu java.lang.Package
, v kombinácii s manifestami v JAR archívoch.
Zistenie verzie knižnice
Týmto spôsobom vieme veľmi jednoducho zistiť verziu napr. logovacej knižnice Commons Logging-u. Zaveďme ho do projektu: buď tak, že ho zavedieme do CLASSPATH
ako knižnicu alebo využijeme správcu závislostí, napríklad Maven::
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sk.upjs.ics.novotnyr</groupId>
<artifactId>manifest-version-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
</dependencies>
</project>
Potom si môžeme vytvoriť ukážkovú triedu:
package sk.upjs.ics.novotnyr.mvd;
import org.apache.commons.logging.Log;
public class CommonsLoggingVersion {
public static void main(String[] args) {
String implementationVersion = Log.class.getPackage().getImplementationVersion();
System.out.println(implementationVersion);
}
}
Ak ju spustíme, výsledok v konzole bude:
1.1.3
Informácia sa nevycucala z prsta, ale z manifestu, teda zo súboru MANIFEST.MF
, ktorý sa nachádza v adresári META-INF
v archíve commons-logging-1.1.3.jar
.
Presnejšie, zoberieme ľubovoľnú triedu z JAR archívu, o ktorom chceme získať verzionovacie informácie (trieda org.apache.commons.logging.Log
je dobrý kandidát), získame inštanciu objektu Class
príslušnej triedy a z nej získame objekt pre balíček, teda Package
.
Pomocou neho sa automaticky naparsuje manifest príslušného archívu. V našom príklade je manifest značne komplikovaný, ale stačí si všímať pasáže:
Implementation-Title: Commons Logging
Implementation-Vendor: The Apache Software Foundation
Implementation-Vendor-Id: org.apache
Implementation-Version: 1.1.3
Trieda java.lang.Package
dokáže spracovať hlavičku Implementation-Version
, načítať ju a priamo k nej pristúpiť. Nemusíme teda pracne načítavať manifesty, hľadať ich umiestnenia a riešiť ich parsovanie: to všetko sa spraví za nás.
Pozor však! Toto funguje len pre manifesty v JAR archívoch!
Vlastný projekt s verziou [pomocou Mavenu]
Niečo podobné vieme dosiahnuť za pomoci Mavenu. Budeme potrebovať:
- vygenerovať manifest
- nakonfigurovať JAR plug-in v
pom.xml
- vytvoriť triedu, ktorá vypíše verziu za behu
Generovanie manifestu
Generovanie manifestu zaistí plug-in pre tvorbu JAR-ov. Tento krok je teda jednoduchý.
Konfigurácia JAR plug-inu v pom.xml
Do pom.xml
stačí zaviesť nový plug-in:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
Stačí dodať klauzulu addDefaultImplementationEntries
, ktorou zapneme generovanie hlavičiek do automaticky vytváraného manifestu.
Ak zostavíme projekt cez mvn package
, výsledkom bude JAR archív s automaticky generovaným manifestom:
Manifest-Version: 1.0
Implementation-Title: manifest-version-demo
Implementation-Version: 0.0.1-SNAPSHOT
Implementation-Vendor-Id: sk.upjs.ics.novotnyr
Built-By: rn
Build-Jdk: 1.7.0_25
Created-By: Apache Maven 3.0.5
Archiver-Version: Plexus Archiver
Vytvorenie triedy, ktorá vypíše verziu za behu
Toto sme už videli v predošlej sekcii:
package sk.upjs.ics.novotnyr.mvd;
public class Version {
public static void main(String[] args) {
Package aPackage = Version.class.getPackage();
String implementationVersion = aPackage.getImplementationVersion();
System.out.println(implementationVersion);
}
}
Spustenie projektu
Ak chceme spustiť projekt, musíme ho zostaviť ako JAR. V samotnom IDE fungovať nebude — výsledkom na konzole bude null
— pretože parsovanie manifestu funguje výhradne v JAR archívoch. (Inými slovami, ak spustíte Version
z Eclipsu, uvidíte null
.)
To však neprekáža:
- zostavíme projekt cez
mvn package
. Výsledkom bude `manifest-version-demo-0.0.1-SNAPSHOT.jar, ktorý… … spustíme cez
java -cp target\manifest-version-demo-0.0.1-SNAPSHOT.jar sk.upjs.ics.novotnyr.mvd.Version
Výsledkom tak bude:
0.0.1-SNAPSHOT
Potřeboval jsem něco podobného získavat z WAR/META-INF/MANIFEST.MF. No, to už tak jednoduché není.
To by som vyriešil asi cez ServletContext a getResource(), to by malo vidieť do WARu a jeho adresárovej štruktúry, a potom sa veseliť s InputStreamami a triedou java.util.jar.Manifest
My jsme před lety řešili něco podobného – řešení jsem popsal zde:
http://blog.novoj.net/2008/08/17/elegantni-zpusob-ukladani-verzi-v-java-archivech/
Takže potvrzuji, je to funkční řešení … :)