有没有办法与提供商绑定解释Google Guice中目标的注释值?
示例:
bind(Resource.class)
.annotatedWith(MyAnnotation.class)
.toProvider(new MyProvider<MyAnnotation, Resource>{
public Resource get(MyAnnotation anno){
return resolveResourceByAnnoValue(anno.value());
}
});
我想通过带注释的绑定初始化Android Activity类的字段。 它必须通过它的唯一ID来获取多个资源。
原创方式:
public class TestActivity extends Activity{
private TextView textView;
private Button testButton;
public void onAfterCreate(...){
// set UI declaration resource.
setContentView(R.layout.activity_test);
// initialize fields, it must be done after setting ui definition.
textView = (TextView) findViewById(R.id.textView);
.... initialize other fields, hook them...
...
}
我想以声明的方式绑定UI及其字段,而不是实际上喜欢上面的内容:
@ResourceID(R.layout.activity_test)
public class TestActivity extends InjectiveActivity{
@ResourceID(R.id.textView) // Auto generated static resource id constant
private TextView textView;
@ResourceID(R.id.testButton)
private Button testButton;
...
}
答案 0 :(得分:2)
这是不可能的。
如果@MyAnnotation
是绑定注释,则会使用其equals
方法进行比较。 @MyAnnotation(5) Resource
将绑定到@MyAnnotation(5) Resource
,与@MyAnnotation(6) Resource
相比,它将完全不匹配。查看this SO answer了解更多信息。在该答案中,如果您愿意,可以遍历可能的注释值并单独绑定每个注释值。
如果@MyAnnotation
不是绑定注释,您将无法从提供商处访问它。如this SO answer中所述,将注入站点信息添加到提供程序或依赖项本身是a rejected feature。
最好的办法是创建一个@Assisted
injection(或手动工厂)来接受参数:
class MyConsumer {
final Resource resource;
@Inject MyConsumer(Resource.Factory resourceFactory) {
int previouslyAnnotatedValue = 5;
this.resource = resourceFactory.createWithValue(previouslyAnnotatedValue);
}
}
您也可以考虑使用Custom Injections,这将允许您使用除@Inject
之外的任意注释,这可能会使用您想要的运行时注释值。< / p>
答案 1 :(得分:0)
以下是Scala中的一个示例(我喜欢使用Scala进行原型设计,毕竟这是一个不同的服装中的Java),我在Dynamic Google Juice injection depending on value of an annotation
中自己想知道它之后提出了这个问题。import java.lang.reflect.{Constructor, Parameter}
import java.util.concurrent.atomic.AtomicReference
import javax.inject.{Inject, Named, Provider}
import com.google.inject.matcher.Matchers
import com.google.inject.spi.ProvisionListener.ProvisionInvocation
import com.google.inject.{AbstractModule, Binder, Guice}
import com.google.inject.spi.{DependencyAndSource, ProviderInstanceBinding, ProvisionListener}
import com.typesafe.config.ConfigFactory
import net.codingwell.scalaguice.InjectorExtensions._
import net.codingwell.scalaguice.ScalaModule
import scala.collection.JavaConverters._
object GuiceExperiments extends App {
val injector = Guice.createInjector(new MyModule())
val some = injector.instance[Some]
println(some)
some.go()
}
trait Some {
def go(): Unit
}
class Impl @Inject()(
@Named("a.a.a") hello: String,
@Named("a.a.b") bello: String,
@Named("a.b.a") kello: String
) extends Some {
override def go() = {
println(hello)
println(bello)
println(kello)
}
}
abstract class DynamicProvider[T >: Null](binder: Binder) extends Provider[T] {
private[this] val nextValue = new AtomicReference[T]
binder.bindListener(Matchers.any(), new ProvisionListener {
private[this] def tryProvide(target: DependencyAndSource): Unit = {
val dependency = target.getDependency
val injectionPoint = dependency.getInjectionPoint
val parameterIndex = dependency.getParameterIndex
injectionPoint.getMember match {
case constructor: Constructor[_] =>
val parameter = constructor.getParameters()(parameterIndex)
nextValue.set(getFor(parameter))
}
}
override def onProvision[V](provision: ProvisionInvocation[V]): Unit = {
provision.getBinding match {
case binding: ProviderInstanceBinding[_] if binding.getUserSuppliedProvider eq DynamicProvider.this =>
provision.getDependencyChain.asScala.lastOption.foreach(tryProvide)
case _ => ()
}
}
})
final override def get(): T = nextValue.getAndSet(null)
def getFor(parameter: Parameter): T
}
class MyModule extends AbstractModule with ScalaModule {
override def configure(): Unit = {
bind[Some].to[Impl]
bind[String].annotatedWith[Named].toProvider(new DynamicProvider[String](binder) {
override def getFor(parameter: Parameter): String = {
if (parameter.isAnnotationPresent(classOf[Named])) {
parameter.getAnnotation(classOf[Named]).value()
} else {
null
}
}
})
}
}
这只会插入@Named
的值,但看起来非常棒。非常不可能。