Challenge Engineer Life !

エンジニア人生を楽しみたい!仕事や趣味で学んだ技術的なことを書いていくブログです。

Mavenのpom.xmlにあるプロジェクト情報をJSFで表示する

Java EE6で開発中のシステム(APサーバはGlassFish 3.1.2.2)で、後輩から

「pom.xmlに定義しているversionを取得して表示したいが、上手くいかない」

と相談されて調べてみました。

StackOverflowみると、わんさか出てきます(^^;

ベストプラクティスがわからない(^^;そもそもこれだけ同じテーマが乱立する時点で悩ましい気が。

自分の場合は前に書いた「Subversionのリビジョンを画面に表示したいと言われたら…」で使ったmavenのfilterを利用した方法がシンプルで好きだったりします。上記StackOverflowでも結構勧めてる人が多いですし。

NetBeansで新規にJava EE6プロジェクトを作って、手順をまとめてみました。

まずは「ファイル」メニューの「新規プロジェクト」からMavenでWebアプリケーションを作成します。

f:id:kikutaro777:20140131223008j:plain

先に進めてプロジェクト名(今回はMavenProjectInfoとしました)などを入れて、GlassFish 3.1.2.2とJava EE6を選べばOKです。

f:id:kikutaro777:20140131223138j:plain

上記の「ファイル」タブを選んでプロジェクト内のフォルダを展開していき

f:id:kikutaro777:20140131222857j:plain

src/mainで右クリックしてフォルダを新規追加します。名前はresourcesです。

f:id:kikutaro777:20140131223330j:plain

続けて、resourcesフォルダの中にプロパティ・ファイルを作成します。

f:id:kikutaro777:20140131223358j:plain

ファイル名は自由ですが、ここでは「version」としました。

f:id:kikutaro777:20140131223429j:plain

で、こんな感じに

f:id:kikutaro777:20140131223456j:plain

プロパティファイルの中身に

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>

のようにすれば

f:id:kikutaro777:20140131223949j:plain

ちゃんと取れます。pom.xmlは以下です。

f:id:kikutaro777:20140131223938j:plain

さらにartifactIdなんかも、先に作ったプロパティファイルで

version = ${project.artifactId}${project.version}

とか定義すれば

f:id:kikutaro777:20140131224052j:plain

こんな感じです。

ちなみに

相談にきた後輩はStackOverflowにあるMETA-INFフォルダにMANIFEST.MFを吐かせてImplementation-Versionを取得する流れで試してうまくいかなかったとのこと。

自分も以下のように試してみました。

上記で作ったMavenプロジェクトのwarにあるMETA-INFをみると

f:id:kikutaro777:20140131230908j:plain

※古い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をみると

f:id:kikutaro777:20140131231225j:plain

確かに増えてます。あとはこれを管理対象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で確認したところ、ちゃんと動きました(^^;

f:id:kikutaro777:20140202071741j:plain

この辺はアプリケーションサーバのベンダごとに少し差異があるんですかね(^^;

JBossで動きそうなのでpom.xmlにImplementationVersionを出力するように設定したら、APは起動するけどページが上手く表示されず…うーむ、NetBeansからの実行が駄目なのか?ここは手元で確認できずちょっと残念。

とはいえ方法を教えて下さった@kazuhira_rさん、ありがとうございました!!

さらに追記

@kazuhira_rさんと同じようにServletから取得してみたのですが、動きませんでした(^^;なぜ…@kazuhira_rさんがわざわざGlassFishでも試してくださり、Twitterで会話する限り、違いがあるのはNetBeansを介してデプロイしてるか、普通にデプロイしてるかの差ぐらいしかなく、そんなので差がでることないよなぁ、と思って試したのですが

f:id:kikutaro777:20140202225435j:plain

普通にデプロイしたら出た!!な、なぜ。

この辺は難しい(^^;とりあえずServletを使えば取れることがわかったので、よしとしようかな。と。

にほんブログ村 IT技術ブログへ
にほんブログ村 にほんブログ村 IT技術ブログ Javaへ
にほんブログ村