normalian blog

Let's talk about Microsoft Azure, ASP.NET and Java!

Microsoft Azure の Web サイトで CDI と JSF を動かしてみる

JavaEE の実行環境を Microsoft Azure の Web サイト上で稼働させる で TomcatEE が Web サイト上で動作することを紹介できたが、今回は実際に JSFCDI を利用したアプリケーションが動くかを検証する。前回の記事でも記載しているが、TomcatEE における JavaEE の実装は以下になる。

上記の内容は アノテーションで大混乱した JavaEE6 頃の実装だが、めげずにアプリを作成したいと思う。また、今回利用したアプリは https://github.com/normalian/MavenWebApp に配置しているので、別途参照してほしい。

アプリケーションの概要

今回作成したアプリケーションは、以下の様に JSF でのデータバインディングを行い、セッションにデータを格納して次の画面で値を表示する簡単な内容だ。
f:id:waritohutsu:20150104152517p:plain

コードの詳細は GitHub を参照いただくとして、トップ画面の XHTML, Java コードを紹介する。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form>
            Hello from Facelets &amp; Please input message
            <h:inputText value="#{viewDto.message}" /> <br />
            <h:commandButton value="submit" action="#{indexAction.doAction}" />
        </h:form>
    </h:body>
</html>
package com.mycompany.mavenwebapp.common;

import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;

@SessionScoped
@Named
public class ViewDto implements Serializable {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
package com.mycompany.mavenwebapp.action;

import com.mycompany.mavenwebapp.common.ViewDto;
import java.io.Serializable;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

@Named
@RequestScoped
public class IndexAction implements Serializable {

    @Inject
    ViewDto viewDto;

    public String doAction() {
        System.out.println("@@@@@@@@ message = " + viewDto.getMessage());
        return "show.xhtml";
    }
}

ご覧のとおり、JSFCDI を利用した簡単なアプリケーションだ。ローカルの TomcatEE でも動作を確認後、Kudu を利用して D:\home\site\wwwroot\bin\apache-tomee-plus-1.7.1\webapps 以下に war ファイルを配置する。war 配置後は冒頭で記載した様に JSFCDI が正しく動作していることが確認できる。

異常で、Jetty や Tomcat しか動かないと思われた Web サイトでも JavaEE の機能が利用できることが紹介できた。是非皆様もいろんなハックを Web サイト上でやってみよう!

JavaEE の実行環境を Microsoft Azure の Web サイト上で稼働させる

新年初ポストは Web サイトと JavaEE について言及させていただきたい。良い子の諸君は JavaEE といえば GlassFish, WebSphere, JBoss AS, WebLogic (それぞれ正式名称が違うのはご容赦頂きたい)を想像すると思うが、Java EE6 から導入されたWeb Profile の実装である TomcatEE を Web サイト上で稼働させることで JavaEE の機能を利用することが可能となることはご存知だと思う。
今回は Tomcat EE を Web サイト上で稼働させてみるが、2015年1月時点での最新版である TomcatEE 1.7.1 の実装は以下となっているので、おおよそ JavaEE6 の機能が稼働すると考えてよいだろう。

Web サイト上での Tomcat EE の稼働

Tomcat 自体は Web サイトにバンドルされているが、まずは Web サイトのギャラリーから Tomcat を選択して Web サイトを作成する(こちらで web.config が作成されるため、TomcatEE の設定を実施しやすくなる)。
f:id:waritohutsu:20150104010257p:plain
次に、Kudu に接続して以下のコマンドを実行して Web サイト上に Tomcat EE を展開する( TomcatEE の URL はバージョン次第で変えること )。

D:\home\site\wwwroot>dir
 Volume in drive D is Windows
 Volume Serial Number is 746D-E3BB

 Directory of D:\home\site\wwwroot

01/02/2015  04:10 PM    <DIR>          .
01/02/2015  04:10 PM    <DIR>          ..
01/02/2015  04:12 PM    <DIR>          bin
01/02/2015  04:13 PM             4,828 web.config
               1 File(s)          4,828 bytes
               3 Dir(s)     767,229,952 bytes free

D:\home\site\wwwroot>cd bin

D:\home\site\wwwroot\bin>curl -O http://ftp.riken.jp/net/apache/tomee/tomee-1.7.1/apache-tomee-1.7.1-plus.zip
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 41.4M  100 41.4M    0     0  11.0M      0  0:00:03  0:00:03 --:--:-- 11.1M

D:\home\site\wwwroot\bin>unzip apache-tomee-1.7.1-plus.zip 

次に、D:\home\site\wwwroot\web.config を以下のように編集する。CATALINA_HOME を編集している点に注目してほしい。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <handlers>
            <add name="httpPlatformHandler" path="*" verb="*" 
                 modules="httpPlatformHandler" resourceType="Unspecified" />
        </handlers>
        <httpPlatform processPath="dd:\home\site\wwwroot\bin\apache-tomee-plus-1.7.1\bin\startup.bat">
            <environmentVariables>
                <environmentVariable name="CATALINA_OPTS" value="-Dport.http=%HTTP_PLATFORM_PORT%" />
                <environmentVariable name="CATALINA_HOME" value="d:\home\site\wwwroot\bin\apache-tomee-plus-1.7.1" />                
                <environmentVariable name="JAVA_OPTS" 	  value="-Djava.net.preferIPv4Stack=true" />
            </environmentVariables>
        </httpPlatform>
    </system.webServer>
</configuration>

更に、D:\home\site\wwwroot\bin\apache-tomee-plus-1.7.1\conf\server.xml を以下のように編集する(抜粋しているので注意してほしい)。Connector タグの port 属性を 8080 から #{port.http} に編集している点に注意してほしい。

        <Connector port="${port.http}" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
        <!-- A "Connector" using the shared thread pool-->

ここで Azure の管理ポータルより当該 Web サイトを再起動する。再起動後、Web サイトにアクセスすることで TomcatEE となっていることが確認できる。
f:id:waritohutsu:20150104010332p:plain

NetBeans 8.0.1 で JavaEE7 な CDI を利用する際の注意点

NetBeansJavaEE 開発にとってなくてはならない優秀な IDE だが、CDI を利用する場合に注意点が存在する。JavaEE6 以降ではすっかり主軸となった CDI についての注意点を紹介する。

新規プロジェクト作成時の注意点

新規プロジェクトから以下の「Webアプリケーション」を選んだ場合、CDI のライブラリに参照が張られない点だ。
f:id:waritohutsu:20141222115117p:plain

cdi-api.jar への参照が存在しないため、CDI を管理コンテナとして明示する以下のアノテーションが利用できない。

  • @javax.enterprise.context.RequestScoped
  • @javax.enterprise.context.SessionScoped
  • @javax.enterprise.context.ApplicationScoped

一方で、以下の JSF 2.0 の管理コンテナを利用するアノテーションは指定できてしまうので注意が必要だ(以下のアノテーションを利用しても、CDI の @Inject ではインスタンスを利用できない)。

  • @javax.faces.bean.RequestScoped
  • @javax.faces.bean.SessionScoped
  • @javax.faces.bean.ApplicationScoped

この辺りの情報は 大混乱に陥っているJavaEE 6のアノテーションに関する使い分けについて が詳しい。

どう解決したらいいの?

以下の様に新規プロジェクトから Maven の Web アプリケーションを選択し、pom.xml を記載して参照を解決すればよい。
f:id:waritohutsu:20141222115127p:plain

pom.xml は以下の様に記載する。CDI のバージョンが 1.2 よりも新しくなったら別途追記してほしい。

<?xml version="1.0" encoding="UTF-8"?>
<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>com.mycompany</groupId>
    <artifactId>MavenWebApp</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>MavenWebApp</name>

    <dependencies>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>7.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.enterprise</groupId>
            <artifactId>cdi-api</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

/// 中略

Java API for JSON Processing(JSR 353) を利用してASP.NET と疎通してみる

今回は ASP.NET Calendar 2014 の14日目である。今回は ASP.NETJava EE 系の連携方法についての紹介を記載する。昨今の REST API ブームに乗っ取り、JSON 形式でデータのやり取りをすることが非常に多い。.NET Framework 側では Json.NET が有名だが、Java 側も JSON を処理する API が提供されたので、今回は .NET Framework と Java EE の連携を実装する。

クライアント .NET Framework, サーバ側 Java EE

(記載中)

クライアント Java EE, サーバ側 .NET Framework

(記載中)

まとめ

(記載中)

Azure Web サイトで Jenkins を無料で稼働させてストレージサービスにデータをアップロードする

本日の記事は Azure Advent Calendar の14日目となる。今回は以下の様に Webサイト 上に Jenkins を配置し、ジョブ実行時にデータを Azure ストレージサービスにアップロードするまでを紹介する。

構築手順の概要は?

Webサイトは JDKTomcat が標準で配置されているが、以下の様に Jenkins や Jenkins Plugin は配置されていない。
f:id:waritohutsu:20141214121627p:plain
したがって以下の流れとなる。

  • Jenkins 配置向けの Webサイト を新規作成する
    • フォルダ作成、モジュール配置
    • 環境変数の設定
  • Jenkins を設定し、Azure ストレージ上にアップロードできるようにする
    • Jenkins 向けのストレージサービスを新規作成
    • Azure Storage プラグインの設定
    • ジョブの作成
    • ジョブの実行

Jenkins 配置向けの Webサイト を新規作成する

まず、管理ポータルから新規に Webサイト を作成(今回は normalian-jenkins という名前にした)し、以下の様に Tomat を有効化する(JDKTomcat のバージョンがちょっと古いのはご容赦願いたいが、自前でモジュールを配置すればもちろん最新版が利用可能だ)。
f:id:waritohutsu:20141214121828p:plain
更に、以下を参考に HUDSON_HOME と JAVA_OPTS の環境変数を設定する。以下の設定を行わない場合、Jenkins がエラーを出力して起動しないので要注意だ( Jetty 側は -Djava.net.preferIPv4Stack=true が元々オプションに入っているのに、なぜか Tomcat 側は入っていない)。
f:id:waritohutsu:20141214122105p:plain

次に、Kudu にログインしてする。Kudu を知らないのは Azure 界の著名人が記載する Windows Azure Web Sitesの魅力を120%引き出す を参照すること。Kudu の Debug console タブから移動し、以下の様に HUDSON_HOME 環境変数向けのフォルダを作成する。なお、Ant や Maven は必要な場合はフォルダを作成し、モジュールを配置すること。
f:id:waritohutsu:20141214122148p:plain

更に、webapp\ROOT の直下に jenkins.war モジュールの中身を配置する。一番簡単な方法は jenkins.war を jenkins.zip にリネームし、モジュールの中身を引っこ抜いてコピーすればよい。
f:id:waritohutsu:20141214122254p:plain

ここまで設定した後、Azure 管理ポータルから Jenkins の設定をした Webサイト を再起動してアクセスする。以下のような画面がでるのでしばらく待ってほしい。
f:id:waritohutsu:20141214122406p:plain

しばらくすると、以下の画面が表示されるので設定完了となる。
f:id:waritohutsu:20141214122442p:plain

Web サイトはインターネット上に公開されているため、ユーザ作成を含む最低限のセキュリティ設定(Jenkins) を参照して登録されたユーザのみログインすることが可能となる(が、https にすらなっていないので、あくまで最低限)。

Jenkins を設定し、Azure ストレージ上にアップロードできるようにする

先ほどまでの手順で Webサイト 上に Jenkins の環境が構築されたので、次は Jenkins 自体の設定を行う。
まずは Jenkins Plugin 向けのストレージサービスを新規に作成する(名前は任意でよい)が、こちらは一般的な方法なので手順は割愛する。
次に、以下の流れで Azure Storage Plugin をインストールする。

  • Jenkins のダッシュボードで、[Jenkins の管理] を押下する。
  • [Jenkins の管理] ページで [プラグインの管理] を押下する。
  • [利用可能] タブをクリックします。
  • [Windows Azure Storage plugin] で検索し、Microsoft Azure ストレージ プラグインを確認する。
  • [再起動せずにインストール] か [ダウンロードして再起動後にインストール] のどちらか押下してインストールを行う。

次に、[Jenkinsの管理]-[Jenkinsの管理] の Microsoft Azure Storage Account Configuration セクションで以下を参考に設定を行う。
f:id:waritohutsu:20141214122519p:plain

さらに、Jenkins のダッシュボードから [新規ジョブ作成]を選択し、[フリースタイル・プロジェクトのビルド]を選択し、以下を参考に情報を設定する。
f:id:waritohutsu:20141214122555p:plain

こちらについてはの詳細な手順は Jenkins 継続的インテグレーション ソリューションでの Azure ストレージの使用にもあるので合わせて参考にすること。
以上の設定が終わった状態から作成したジョブから [ビルドの実行] を選択するとストレージサービスにジョブで設定したファイルがアップロードされる。まずは Jenkins のジョブのページを確認すると、以下のようにジョブの実行結果が確認される。
f:id:waritohutsu:20141214122648p:plain

更に、ストレージサービスを確認するとモジュールがアップロードされていることが確認できる。
f:id:waritohutsu:20141214122754p:plain

終わりに

今回は無料で Azure Webサイト上に Jenkins 環境が構築できることを紹介した。こちらに対し、さらに NEXUS を追加 したり、Github の Jenkins plugin を追加しても面白いだろう。

JavaEE7 で CDI の Interceptor を味わってみる

Java EE6 から導入された CDI のインターセプタだが( JavaEE5 までは EJB インターセプタしか存在しなかった)、JavaEE7 で改良が加えられているので紹介する。今回紹介する内容は以下の二点になる。

こちらをそれぞれ試してみる

ソースコード

今回作成したソースコードの動作イメージは以下となる。
f:id:waritohutsu:20141211154727p:plain

次に、動作に必要なソースコードは以下になる。beans.xml が不要な点に注意が必要だ。

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <h:head>
        <title>Facelet のインターセプタを学ぶ</title>
    </h:head>
    <h:body>
        <h:form>
            Hello Facelets: 今は <h:outputText value="#{listAction.count}" />回目<br />
            <h:commandButton value="加算" action="#{listAction.countUp()}" />
        </h:form>
    </h:body>
</html>
package com.mydomain.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;

@Inherited
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Logged {
}
package com.mydomain.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;

@Inherited
@InterceptorBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface SecondLogged {
}
  • LoggedInterceptor.java
package com.mydomain.interceptors;

import com.mydomain.annotations.Logged;
import java.io.Serializable;
import javax.annotation.Priority;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;


@Priority(Interceptor.Priority.LIBRARY_BEFORE)
@Interceptor
@Logged
public class LoggedInterceptor implements Serializable {

    public LoggedInterceptor() {

    }
    @AroundInvoke
    public Object logMethodEntry(InvocationContext ic) throws Exception {
        System.out.println("$$Logged Interceptor, before: "
                + ic.getMethod().getName() + " in class "
                + ic.getMethod().getDeclaringClass().getName());
        Object obj = ic.proceed();
        System.out.println("$$Logged Interceptor, after: "
                + ic.getMethod().getName() + " in class "
                + ic.getMethod().getDeclaringClass().getName());
        return obj;
    }
}
  • SecondLoggedInterceptor.java
package com.mydomain.interceptors;

import com.mydomain.annotations.SecondLogged;
import java.io.Serializable;
import javax.annotation.Priority;
import javax.interceptor.AroundInvoke;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;

@Priority(Interceptor.Priority.APPLICATION)
@Interceptor
@SecondLogged
public class SecondLoggedInterceptor implements Serializable {

    @AroundInvoke
    public Object logMethodEntry(InvocationContext ic) throws Exception {
        System.out.println("@@SecondLogged Interceptor, before: "
                + ic.getMethod().getName() + " in class "
                + ic.getMethod().getDeclaringClass().getName());
        Object obj = ic.proceed();
        System.out.println("@@SecondLogged Interceptor, after: "
                + ic.getMethod().getName() + " in class "
                + ic.getMethod().getDeclaringClass().getName());
        return obj;
    }
}
package com.mydomain.action;

import com.mydomain.annotations.SecondLogged;
import com.mydomain.annotations.Logged;
import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named
@ViewScoped
public class ListAction implements Serializable {

    private int count;

    @Logged
    @SecondLogged
    public String countUp() {
        System.out.println("★★★ListAction#countUp, count = " + count);
        setCount(getCount() + 1);
        return "";
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}


上記を動作させた場合の実行結果はいかになる。

情報:   $$Logged Interceptor, before: countUp in class com.mydomain.action.ListAction
情報:   @@SecondLogged Interceptor, before: countUp in class com.mydomain.action.ListAction
情報:   ★★★ListAction#countUp, count = 0
情報:   @@SecondLogged Interceptor, after: countUp in class com.mydomain.action.ListAction
情報:   $$Logged Interceptor, after: countUp in class com.mydomain.action.ListAction

インターセプタの順番を決める Priority は値が大きいほど優先度が高く、あらかじめ用意されている定数は以下になる。

定数名
PLATFORM_BEFORE 0
LIBRARY_BEFORE 1000
APPLICATION 2000
LIBRARY_AFTER 3000
PLATFORM_AFTER 4000

JavaEE7 な JSF 2.2 の ViewScoped を試してみる

今回はふと JavaEE を弄っていてちょっとはまってしまったポイントについて紹介する。JavaEE 有識者各位ならば J2EE 時代の XML 地獄を脱却するため、JavaEE5 からはアノテーションによる規約ベースの設定を重視する文化になったことはご存じだと思うが、特に JSF には以下の闇がある。

  • JSF 1.0(JavaEE5 時代):DI コンテナがなく(厳密には JBoss Seam が存在したが、Java EE の仕様に入っていなかった)、ManagedBean は faces-config.xmlXML ベースで設定
  • JSF 2.0(JavaEE6 時代):DI コンテナ(CDI)が導入されたが、JSF 2.0 のアノテーションCDIアノテーションが混在し、更に JSF の機能と CDI の機能に差があった
  • JSF 2.2(JavaEE7 時代):JavaEE6 時代の問題を大体解決(原則 CDI 側に寄せた)したが、若干名残あり

特に、JavaEE6 時代の闇については 達人プログラマーを目指して > 大混乱に陥っているJavaEE 6のアノテーションに関する使い分けについて達人プログラマーを目指して > Java EE6環境でJSF2を使う場合はCDIのBeanを管理Beanとして使う方がよい が詳しい。

今回は JSF 2.2 より CDI compatible @ViewScoped が存在するので、そちらを確認してみる。

サンプルコード

ManagedBean 相当の Java ファイルと画面相当 xhtml ファイルは以下となる。 MessageAction.java の ①~④のアノテーションを組み合わせて検証する。

  • MessageAction.java
package mysample.app.action;

import java.io.Serializable;
//① import javax.faces.view.ViewScoped;
//② import javax.faces.bean.ManagedBean;
//③ import javax.faces.bean.ViewScoped;
//④ import javax.inject.Named;

//@ManagedBean
@ViewScoped
@Named
public class MessageAction implements Serializable {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String doAction() {
        System.out.println("message at MessageAction#doAction = " + message);
        return null;
    }
}
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
    <h:head>
        <title>My Sample</title>
        <style type="text/css">
            .strike{
                text-decoration: line-through;
            }
        </style>            
    </h:head>
    <h:body>
        <h2>Scope Confrim</h2>
        <h:messages layout="table" styleClass="alert" />
        <h:form>
            <h:panelGrid columns="2">
                <h:outputLabel value="Title: "/>
                <h:inputText value="#{messageAction.message}" p:placeholder="please input text" />
                <h:commandButton value="DoAction" action="#{messageAction.doAction()}" />
            </h:panelGrid>
        </h:form>
    </h:body>
</html>

上記のうち、p:placeholder と javax.faces.view.ViewScoped は JSF 2.2 からの新機能だ。こちらのコードを利用した実行結果は以下となる。

  • ①+④:「情報: message at MessageAction#doAction = <入力値>」が出力
  • ①+②:「情報: message at MessageAction#doAction = null」が出力
  • ②+③:「情報: message at MessageAction#doAction = <入力値>」が出力
  • ③+④:「情報: message at MessageAction#doAction = null」が出力

なんでこうなるの?

冒頭で語った JSF の闇に記載した通り、JSF のライフサイクルと CDI のライフサイクルのどちらを利用するかで必要なアノテーションの組み合わせが異なるためだ。

javax.faces.view.ViewScoped & javax.inject.Named は CDI を利用したライフサイクルになる。以下に javax.faces.view.ViewScoped に対するコメントを抜粋する。

import javax.faces.view.ViewScoped;

When this annotation, along with javax.inject.Named is found on a class, the runtime must place the bean in a CDI scope such that it remains active as long as NavigationHandler.handleNavigation(javax.faces.context.FacesContext, java.lang.String, java.lang.String) does not cause a navigation to a view with a viewId that is different than the viewId of the current view. Any injections and notifications required by CDI and the Java EE platform must occur as usual at the expected time.


また、javax.faces.bean.ViewScoped & javax.faces.bean.ManagedBean の場合は JSF を利用したライフサイクルになる。以下に javax.faces.bean.ViewScoped に対するコメントを抜粋する。

import javax.faces.beans.ViewScoped;

When this annotation, along with ManagedBean is found on a class, the runtime must act as if a <managed-bean-scope>view<managed-bean-scope> element was declared for the corresponding managed bean.

更に、上記で検証した通り JSF 向けのアノテーションCDIアノテーションを組み合わせた場合はデータバインディングがうまく動かない点に注意が必要だ。
JSFCDI を利用する際の問題は、他のスコープについてのアノテーション(リクエストスコープ、セッションスコープ、アプリケーションスコープ)にも存在するため、これらのアノテーションの使い分けに注意してほしい。