JavaEE 7をやってみよう。 CDI その2
その1のつづき。
その1に書いたサンプルは、
インターフェイスに対して実装クラスが1つしかなかったが、
複数の実装を持つインターフェイスはどうインジェクションされるのだろう。
Springだとコンフィグに書いた記憶もあるが、詳しくは忘れた。
ここではJavaEEの作法を覚えるので、まぁ、いい。
JavaEEでは限定子というものを作り、
それを対象に貼り付けることでインジェクション対象を明確にする。
書いていてよくわからないが、読んでいてもわかりづらい。
ソースを書こう。
まず、限定子を作る。
新規ウィザードからCDI(Context and Dependency Injection)グループの中の
Qualifier Annotationを選び、
パッケージ名と限定子名を決め、完了を押すと自動生成される。
- ・QRichText限定子
- 限定子についてるアノテーションについては、
@Target…型、メソッド、パラメタ、フィールドの優先順序でクラスを決める、
@Retention…VM起動中の間
ってな意味ですかね。
詳しくはドキュメントを読む必要があるけれど、今はこのままで。
package text.qualifier; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.inject.Qualifier; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Qualifier @Target({ TYPE, METHOD, PARAMETER, FIELD }) @Retention(RUNTIME) @Documented public @interface QRichText { }
続いて、その1のサンプルに出したITextインターフェイスの実装をもう1つ作る。
- ・RichTextクラス
- getTextメソッドの処理は、SimpleTextクラスとは実装を変えます。
テスト結果がわかりやすいように。
そして重要なのが、クラスに限定子を付加すること。
package text.impl; import javax.enterprise.context.RequestScoped; import text.qualifier.QText; @RequestScoped @QRichText public class RichText extends SimpleText { private static final String DECORATOR = "-"; @Override public String getText() { String deco = ""; String text = super.getText(); StringBuffer sb = new StringBuffer(); if (text != null) { for (int i = 0; i < text.getBytes().length + 2; i++) { deco += DECORATOR; } sb.append(deco); sb.append("<BR />"); sb.append(DECORATOR); sb.append(text); sb.append(DECORATOR); sb.append("<BR />"); sb.append(deco); sb.append("<BR />"); } return sb.toString(); } }
でもって、Managed Beanも拡張します。
- ・DisplayTextクラス
- SimpleTextクラスとRichTextクラスをDIできるようにITextのメンバを増やします。
そして、一方には、先ほど作った@QRichText限定子を付加します。
これによって、メンバとクラスの関係付けが行われます。目印を付けたってことですか。
『ここには@QRichTextの印をつけたクラスをいれよ』てなことですね。
package manage; import javax.enterprise.context.RequestScoped; import javax.inject.Inject; import javax.inject.Named; import text.IText; import text.qualifier.QRichText; @Named(value="display") @RequestScoped public class DisplayText { @Inject private IText iText; @Inject @QRichText private IText iText2; private String inputText1; /** * inputText1を取得します。 * @return inputText1 */ public String getInputText1() { return inputText1; } /** * inputText1を設定します。 * @param inputText1 inputText1 */ public void setInputText1(String inputText1) { this.inputText1 = inputText1; } public String getText1() { iText.setText(inputText1); return iText.getText(); } public String getText2() { iText2.setText(inputText1); return iText2.getText(); } }
さて、テスト用のJSFを書き換えましょう。
- ・di.xhtml
- docoText1には、SimpleTextクラスの結果が、
decoText2には、RichTextクラスの結果が出るはずです。
<!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" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets"> <h:head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <h:outputStylesheet library="css" name="default.css" /> <title>DIサンプル</title> </h:head> <h:body> <h:form id="form1"> <h:outputLabel value="文字を入力するのだ。" /><br /> <h:inputSecret id="inputText1" value="#{display.inputText1}"> <f:ajax execute="form1" /> </h:inputSecret> <hr/> <h:outputLabel value="ここに入力した文字がでるぞ。" /> <br /> <h:outputText id="decoText1" value="#{display.text1}" escape="false" /> <hr/> <h:outputLabel value="ここにも入力した文字がでるぞ。" /> <br /> <h:outputText id="decoText2" value="#{display.text2}" escape="false" /> </h:form> </h:body> </html>
実行すると、こんな感じです。