動的な値のコンストラクタインジェクション

S2Containerを使って、コンストラクタに動的な値を食わせることはできないだろうか、と考えている。

例えば、0, 1, 2, 3...と、通し番号を生成するクラスがあって。

public class SerialNumberGenerator {
 public static int nextSequence() {
  return ...;
 }
}

そしてその番号を使ったIDを持つクラスがあったとする。

public class Model {

 private final int id;

 public Model(int id) {
  this.id = id;
 }

 public int getId() {
  return id;
 }
}

このModelクラスをS2Containerで管理したい*1

<component class="Model" instance="prototype">
 <arg>@SerialNumberGenerator@nextSequence()</arg>
</component>
Model model = (Model) container.getComponent(Model.class);

こうすることにより、コンストラクタインジェクションにより、getComponentするたびに、新しいIDが振られたModelのインスタンスが出来る。
ところで、IDは一意であるべきなので、基本的にIDの割り振りはSerialNumberGeneratorに任せるのだが、場合によっては「特定のIDを持つModelを作りたい」こともある*2

そういった場合、コンテナを使っていなければ、 以下の2つでモデルの作り分けができるが、コンテナを使った場合はうまく作り分ける事ができないんだろうか…。

// コンテナを使わない場合
Model newModel1 = new Model(SerialNumberGenerator.nextSequence());
Model storedModel1 = new Model(specifiedId);

// コンテナを使う場合
Model newModel2 = (Model) container.getComponent(Model.class);
Model storedModel2 = ...?

ちなみに、「IDは一貫性を保たなければならない」という理由でfinalを外したくない。途中で意図せずIDを変えられてしまうことのないように、少なくともsetterは用意したくないのだ。

SerialNumberGeneratorに細工をするのはお門違いな気がするし、スレッドを考え出すと面倒。「自動採番モデル」と「指定IDモデル」を別コンポーネントで定義すべき? うーん、さてどうしたものか。

*1:この話には出てこないが、AOPを掛ける要件があるので、newする訳にはいかない…

*2:具体的には、外部(例えばXMLや、DB)に保存したデータを元にModelを復元する時など