Java EE6で開発中のシステム(APサーバはGlassFish 3.1.2.2)で、後輩から
「pom.xmlに定義しているversionを取得して表示したいが、上手くいかない」
と相談されて調べてみました。
StackOverflowみると、わんさか出てきます(^^;
ベストプラクティスがわからない(^^;そもそもこれだけ同じテーマが乱立する時点で悩ましい気が。
自分の場合は前に書いた「Subversionのリビジョンを画面に表示したいと言われたら…」で使ったmavenのfilterを利用した方法がシンプルで好きだったりします。上記StackOverflowでも結構勧めてる人が多いですし。
NetBeansで新規にJava EE6プロジェクトを作って、手順をまとめてみました。
まずは「ファイル」メニューの「新規プロジェクト」からMavenでWebアプリケーションを作成します。
先に進めてプロジェクト名(今回はMavenProjectInfoとしました)などを入れて、GlassFish 3.1.2.2とJava EE6を選べばOKです。
上記の「ファイル」タブを選んでプロジェクト内のフォルダを展開していき
src/mainで右クリックしてフォルダを新規追加します。名前はresourcesです。
続けて、resourcesフォルダの中にプロパティ・ファイルを作成します。
ファイル名は自由ですが、ここでは「version」としました。
で、こんな感じに
プロパティファイルの中身に
version = ${project.version}
と定義してみます。Mavenのpom.xmlのprojectで定義されたversionを取ってね、という定義です。
あとは管理対象Beanで例えば
package jp.co.hoge.mavenprojectinfo;
import java.io.IOException;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
import lombok.Getter;
@Named
@RequestScoped
public class IndexBean {
@Getter
private String version;
@PostConstruct
public void init() throws IOException{
Properties prop = new Properties();
prop.load(this.getClass().getResourceAsStream("/version.properties"));
version = prop.getProperty("version");
}
}
みたいにしてJSFのビューで(bodyタグのみ抜粋)
<h:body>
<h:outputText value="#{indexBean.version}" />
</h:body>
のようにすれば
ちゃんと取れます。pom.xmlは以下です。
さらにartifactIdなんかも、先に作ったプロパティファイルで
version = ${project.artifactId}${project.version}
とか定義すれば
こんな感じです。
ちなみに
相談にきた後輩はStackOverflowにあるMETA-INFフォルダにMANIFEST.MFを吐かせてImplementation-Versionを取得する流れで試してうまくいかなかったとのこと。
自分も以下のように試してみました。
上記で作ったMavenプロジェクトのwarにあるMETA-INFをみると
※古いJDK使っててごめんなさいごめんなさい…
こんな感じでした。で、StackOverflowにあるようにmaven-war-pluginで以下のように定義し、warのmanifest.mfに情報を出力するように設定しました。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1.1</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
<archiveClasses>true</archiveClasses>
</configuration>
</plugin>
ビルド後に先ほどと同じMETA-INFをみると
確かに増えてます。あとはこれを管理対象Beanなどからみればいい、と思ったのですが
例えばStackOverflowにもある
this.getClass().getPackage().getImplementationVersion();
みたいな書き方すると、管理対象Beanクラスのパッケージのものをみようとしてnullになります。
他にもgetClass()からgetResourceAsStream()などで読み込むサンプルなどもありますが、うまくいかず。
あと、NetBeansでGlassFishをデバッグモード起動してブレイクポイントおいてるのですが、止まらずに空白ページが起動するとか、よくわからない動きも…。
そもそもGlassFishにデプロイするwarでMETA-INFって…?
今までWEB-INFしか意識してないや…(^^;あれ、あれ、みたいな。
現状の自分はJavaに関してまだまだ全然知識的が足りないのですが、その中でも特にJavaのクラスローダの辺りやGlassFishではそれがどうなっているか、jarやwarの構成と動き、などなど、この辺りの理解が乏しい気がしています。だから、今回のも「こうすればできる」というのが見えていない感じ。
精進あるのみだなぁ…。
追記
@kazuhira_rさんがブログでMANIFEST.MFからの読み込み方法について書いて下さりました(^^)!!!
WARファイルの中にある、MANIFEST.MFファイルの内容を読む
ServletContextを利用、とのこと。
自分はJSF使っているので、ServletContext使えるのかな…と調べたら使えるらしい(^^;
How To Get ServletContext In JSF 2
ということで、まずは以下のように通常のMANIFEST.MFが読めるか確認してみました。
package jp.co.hoge.mavenprojectinfo;
import java.io.IOException;
import java.util.Properties;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Named;
import javax.servlet.ServletContext;
import lombok.Getter;
@Named
@RequestScoped
public class IndexBean {
@Getter
private String manifestVer;
@PostConstruct
public void init() throws IOException{
ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();
Properties manifestProp = new Properties();
manifestProp.load(servletContext.getResourceAsStream("/META-INF/MANIFEST.MF"));
manifestVer = manifestProp.getProperty("Manifest-Version");
}
}
結果的には、GlassFishでは駄目でした。
servletContext.getResourceAsStream("/META-INF/MANIFEST.MF")でnullが返ってきます。
試しにJBossAS 7.1.1で確認したところ、ちゃんと動きました(^^;
この辺はアプリケーションサーバのベンダごとに少し差異があるんですかね(^^;
JBossで動きそうなのでpom.xmlにImplementationVersionを出力するように設定したら、APは起動するけどページが上手く表示されず…うーむ、NetBeansからの実行が駄目なのか?ここは手元で確認できずちょっと残念。
とはいえ方法を教えて下さった@kazuhira_rさん、ありがとうございました!!
さらに追記
@kazuhira_rさんと同じようにServletから取得してみたのですが、動きませんでした(^^;なぜ…@kazuhira_rさんがわざわざGlassFishでも試してくださり、Twitterで会話する限り、違いがあるのはNetBeansを介してデプロイしてるか、普通にデプロイしてるかの差ぐらいしかなく、そんなので差がでることないよなぁ、と思って試したのですが
普通にデプロイしたら出た!!な、なぜ。
この辺は難しい(^^;とりあえずServletを使えば取れることがわかったので、よしとしようかな。と。