Yan Container−Setter Injection

Yan Containerにクラスを登録して使う(2006.9.24)

Yan ContainerはConstructor InjectionだけでなくSetter Injectionも使うことができる.

まず,FishクラスはConstructor Injectionと同様である.FishermanクラスにはFishクラスを設定するためのsetFish(Fish)メソッドが必要である.

//Fish.java Constructor Injectionと同じ.
public class Fish{
  public void fish(Fisherman fisherman){
    System.out.println(this+" was fished by "+fisherman);
  }
}

//Fisherman.java コンストラクタの代わりにsetterを用意.
public class Fisherman{
  Fish fish;

  public void setFish(Fish fish){ //Fishクラスを登録するためのsetterメソッドを追加.
    this.fish=fish;
  }
  public void fish(){
    fish.fish(this);
  }
}

//Main.java
import java.beans.IntrospectionException;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    try{
      yan.registerComponent(Components.bean(Fish.class)); //a. Fishクラスをコンテナに登録
      yan.registerComponent(Components.bean(Fisherman.class)); //b. Fishermanクラスをコンテナに登録
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class); //c. Fishermanクラスのインスタンス生成
    fisherman.fish(); //d. 魚を釣る
  }
}

Mainクラスは以下の手順で魚を釣っている.

  1. Components.bean(java.lang.Class)メソッドを使って使用するクラス(ここではFishクラスとFishermanクラス)に該当するComponentクラスを生成する(Main.javaのaとb)
  2. registerComponent(Component)メソッドを使ってYan Containerに登録する(Main.javaのaとb)
  3. Fishermanクラスのインスタンスを生成(Main.javaのc)
  4. 魚を釣る(Main.javaのc)

このプログラムをコンパイル&実行するとこんな結果になる.魚は釣れたようだ.

Fish@27e353 was fished by Fisherman@bd928a

Fishermanクラスのfish()メソッド実行時に必要なFishクラスのインスタンスは,Yan Containerが自動的に生成する.そして,Fishクラスに定義したsetFish(Fish)メソッドを使ってFishermanクラスのインスタンス変数に設定してくれる.

クラスに特定の値を指定(2006.10.8)

釣れた魚の種類を付け加えよう.Constructor Injectionの場合はコンストラクタを定義するが,Setter InjectionなのでFishクラスにsetterとしてsetKind(String)を追加する.

//Fish.java
public class Fish{
  private String kind;

  public void setKind(String kind){ //魚の種類のsetterを追加
    this.kind=kind;
  }

  public void fish(Fisherman fisherman){
    System.out.println(this+"("+kind+") was fished by "+fisherman); //魚の種類も出力しよう
  }
}

//Fisherman.java −変更なし−
public class Fisherman{
  private String name;
  Fish fish;

  public void setFish(Fish fish){
    this.fish=fish;
  }
  public void fish(){
    fish.fish(this);
  }
}

//Main.java
import java.beans.IntrospectionException;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    yan.registerValue("タイ"); //a. 魚の種類をYan Containerに登録
    try{
      yan.registerComponent(Components.bean(Fish.class));
      yan.registerComponent(Components.bean(Fisherman.class));
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

このプログラムを動かすとこんな結果になる.タイは釣れたようだ.

Fish@27e353(タイ) was fished by Fisherman@bd928a

注意しないといけないのは,Main.javaのaで使っているContainer.registerValueメソッドは

  • FishクラスのsetKind(String)の引数に指定したString型の値

ではなく

  • Containerに登録した全クラスが使うString型の値

を設定していると言う点である.

例えば,FishermanクラスでもString型の引数(釣り人の名前)を持っていたとしよう.

//Fisherman.java
public class Fisherman{
  private String name;
  Fish fish;

  public void setName(String name){ //String型の引数(釣り人の名前)を持つsetter
    this.name=name;
  }
  public String getName(){
    return this.name;
  }
  public void setFish(Fish fish){
    this.fish=fish;
  }
  public void fish(){
    fish.fish(this);
  }
}

Fish.javaで釣上げた人の名前を出力する.

//Fish.java
public class Fish{
  private String kind;

  public void setKind(String kind){
    this.kind=kind;
  }

  public void fish(Fisherman fisherman){
    System.out.println(this+"("+kind+") was fished by "+fisherman+"("+fisherman.getName()+")"); //釣り人の名前を出力
  }
}

Main.javaは同じである.コンパイル&実行してみよう.

Fish@27e353(タイ) was fished by Fisherman@bd928a(タイ)

釣り人の名前もタイになってしまう.

setterで設定するプロパティを指定(2006.10.22)

魚には魚の名前を,釣り人には釣り人の名前を付けよう.Main.javaを修正する.Fish.javaとFisherman.javaは修正不要である.

import java.beans.IntrospectionException;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    try{
      yan.registerComponent(Components.bean(Fish.class)
                            .withProperty("kind",Components.value("タイ")));
                            //a. 第1引数は設定するプロパティの名前.大文字と小文字の区別あり
      yan.registerComponent(Components.bean(Fisherman.class)
                            .withProperty("name",Components.value("浜ちゃん")));
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

Component.withPropertyメソッド(Main.javaのa)を使って,プロパティに値を設定する.withPropertyメソッドの第1引数は設定するプロパティの名前,第2引数は設定する値である.設定する値はComponent型である必要があるので,Components.valueメソッドを使って文字列をComponent型に変換している.

手順を逐一書くならこのようになる.

import java.beans.IntrospectionException;
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    try{
      Component fish=Components.bean(Fish.class);
      fish=fish.withProperty("kind",Components.value("タイ"));
      yan.registerComponent(fish);

      Component fisherman=Components.bean(Fisherman.class);
      fisherman=fisherman.withProperty("name",Components.value("浜ちゃん"));
      yan.registerComponent(fisherman);
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

コンテナから取り出す(Container.getInstanceOfTypeメソッドを使う)のはFishermanオブジェクトだけなので,Fish.classは登録しなくても良い.

import java.beans.IntrospectionException;
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main2{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    try{
      Component fish=Components.bean(Fish.class).withProperty("kind",Components.value("タイ"));
      //Fish.classはコンテナには登録しない.Componentオブジェクトを作成するだけ.
      yan.registerComponent(Components.bean(Fisherman.class)
                            .withProperty("name",Components.value("浜ちゃん"))
                            .withProperty("fish",fish));
      //withPropertyメソッド経由でsetFishメソッドを使い,Fishermanオブジェクトのfishプロパティに値を設定.
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

コンストラクタとbean(2006.11.5)

JavaBeanでは,使用できるコンストラクタはパラメータのないコンストラクタのみである.しかし,Yan Containerでは,パラメータのあるコンストラクタをもつbeanを使うこともできる.

まず,FishクラスとFishermanクラスにコンストラクタを定義しよう.

//Fish.java
public class Fish{
  private String kind;

  public Fish(){ //デフォルトコンストラクタを追加
  }
  public Fish(String kind){ //パラメータのあるコンストラクタを追加
    this.setKind(kind);
  }
  public void setKind(String kind){
    this.kind=kind;
  }
  public void fish(Fisherman fisherman){
    System.out.println(this+"("+kind+") was fished by "+fisherman+"("+fisherman.getName()+")");
  }
}

//Fisherman.java
public class Fisherman{
  private String name;
  Fish fish;

  public Fisherman(){ //デフォルトコンストラクタを追加
  }
  public Fisherman(String name,Fish fish){ //パラメータのあるコンストラクタを追加
    this.setName(name);
    this.setFish(fish);
  }
  public void setName(String name){
    this.name=name;
  }
  public String getName(){
    return this.name;
  }
  public void setFish(Fish fish){
    this.fish=fish;
  }
  public void fish(){
    fish.fish(this);
  }
}

[setterで設定するプロパティを指定]で使用したMain.javaをそのまま使ってみよう.

//Main.java
import java.beans.IntrospectionException;
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    try{
      Component fish=Components.bean(Fish.class).withProperty("kind",Components.value("タイ"));
      yan.registerComponent(Components.bean(Fisherman.class)
                            .withProperty("name",Components.value("浜ちゃん"))
                            .withProperty("fish",fish));
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

これを実行するとこんな結果になる.

Fish@153f67e(タイ) was fished by Fisherman@15bdc50(浜ちゃん)

FishクラスとFishermanクラスをbeanとして扱うためにはデフォルトコンストラクタ(引数のないコンストラクタ)が必須である.これがなかった場合,以下のようにIllegalArgumentExceptionが発生する.

java.lang.IllegalArgumentException: constructor not found for: Fish()
    at org.apache.tools.ant.taskdefs.ExecuteJava.execute(ExecuteJava.java:180)
    at org.apache.tools.ant.taskdefs.Java.run(Java.java:710)
    at org.apache.tools.ant.taskdefs.Java.executeJava(Java.java:178)

    at org.apache.tools.ant.taskdefs.Java.execute(Java.java:84)
    at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:275)
    at org.apache.tools.ant.Task.perform(Task.java:364)

コンストラクタインジェクションでも使うことができる.Fish.javaとFisherman.javaには変更はない.

//Main2.java
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main2{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    Component fish=Components.ctor(Fish.class,new Class[]{String.class})
      .withArgument(0,Components.value("タイ"));
    yan.registerComponent(Components.ctor(Fisherman.class,new Class[]{String.class,Fish.class})
                          .withArgument(0,Components.value("浜ちゃん"))
                          .withArgument(1,fish));
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

実行するとこんな結果になる.

Fish@fe748f(タイ) was fished by Fisherman@1968e23(浜ちゃん)

コンストラクタインジェクションで作成したComponentに,beanとしてプロパティを設定することもできる.

import java.beans.IntrospectionException;
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.containers.DefaultContainer;

public class Main3{
  public static void main(String[] args){
    Container yan=new DefaultContainer();
    Component fish=Components.ctor(Fish.class,new Class[]{String.class})
      .withArgument(0,Components.value("タイ"));
    Component fisher=Components.ctor(Fisherman.class,new Class[]{String.class,Fish.class})
      .withArgument(0,Components.value("浜ちゃん"))
      .withArgument(1,fish);  //コンストラクタインジェクションでComponentを作成
    try{
      fisher=Components.bean(fisher)
        .withProperty("name",Components.value("スーさん"))
        .withProperty("fish",fish); //beanとしてプロパティを設定.
    }
    catch(IntrospectionException e){
      e.printStackTrace();
    }
    yan.registerComponent(fisher);
    Fisherman fisherman=(Fisherman)yan.getInstanceOfType(Fisherman.class);
    fisherman.fish();
  }
}

実行するとこうなる.当然といえば当然だが,後から設定したプロパティが有効である.

[java] Fish@19836ed(タイ) was fished by Fisherman@3e0ebb(スーさん)