最近、なんとなくMicronautを触り始めてる。
## 気になった
順番にドキュメントを読んでいってて、この部分が気になった。
https://docs.micronaut.io/latest/guide/index.html#qualifiers
import javax.inject.* interface Engine { int getCylinders() String start() } @Singleton class V6Engine implements Engine { int cylinders = 6 String start() { "Starting V6" } } @Singleton class V8Engine implements Engine { int cylinders = 8 String start() { "Starting V8" } } @Singleton class Vehicle { final Engine engine @Inject Vehicle(@Named('v8') Engine engine) { this.engine = engine } String start() { engine.start() } }
Engine
の実装として、V6Engine
とV8Engine
が定義されていて、@Named
アノテーションで名前を指定してInjectできるよ、という部分。
この「名前」の部分、どういう動きでv8
だけで取得できるんだろう?というのが気になった。v8engine
だったらクラス名かなーと思うんだけど。
## とりあえず動かす
サンプルコードはGroovyかな?なので、セミコロンを後ろにつけたりして、手元にあったHelloController
にコンストラクターインジェクションで差し込んでみた。
package hello.world; import io.micronaut.http.MediaType; import io.micronaut.http.annotation.*; import javax.inject.*; @Controller("/hello") public class HelloController { final Engine engine; HelloController(@Named("v8") Engine engine){ this.engine = engine; } @Get(produces = MediaType.TEXT_PLAIN) public String index() { return "Hello World. " + engine.start(); } } interface Engine { int getCylinders(); String start(); } @Singleton class V6Engine implements Engine { int cylinders = 6; @Override public int getCylinders() { return cylinders; } @Override public String start() { return "Starting V6"; } } @Singleton class V8Engine implements Engine { int cylinders = 8; @Override public int getCylinders() { return cylinders; } @Override public String start() { return "Starting V8"; } }
- 確かに
v8
だけで動く v6
を指定するとV6Engine
になるv8engine
でも動く- 前方一致なのかな?と思って
v8eng
にしてみたら動かない
ほほー。
## 実装クラスに名前を指定
@Named
アノテーションをつけると実装クラスに名前をつけることができる。
@Singleton @Named("sss") class V8Engine implements Engine { int cylinders = 8;
sss
でInjectできるv8
ではInjectできなくなったv8engine
でもInjectできなくなった
なるほどー。
## ということで実装を探した
ここだな。
String typeName; AnnotationMetadata annotationMetadata = candidate.getAnnotationMetadata(); // here we resolved the declared Qualifier of the bean Optional<String> beanQualifier = annotationMetadata.findDeclaredAnnotation(Named.class).flatMap(namedAnnotationValue -> namedAnnotationValue.getValue(String.class)); typeName = beanQualifier.orElseGet(() -> { if (candidate instanceof NameResolver) { Optional<String> resolvedName = ((NameResolver) candidate).resolveName(); return resolvedName.orElse(candidate.getBeanType().getSimpleName()); } return candidate.getBeanType().getSimpleName(); }); return typeName.equalsIgnoreCase(name) || typeName.equalsIgnoreCase(name + beanType.getSimpleName()); }
- 実装クラスに
@Named
がついてる場合は- 1-1. 指定した名前が、
@Named
のvalue
と一致すればOK
- 1-1. 指定した名前が、
- 実装クラスに
@Named
がついていない場合は- 2-1. 指定した名前が、大文字小文字を無視して実装クラスのSimpleNameと一致すればOK
- 2-2. 指定した名前 + BeanTypeのSimpleNameが、大文字小文字を無視して実装クラスのSimpleNameと一致すればOK
そっかー。だからv8
だけを指定した場合は、2-2で、v8
にEngine
インターフェース名がくっついたものと一致してるってことか。
すっきり。