Java 如何使用Guice注入索引(和特定于类的)字符串

Java 如何使用Guice注入索引(和特定于类的)字符串,java,dependency-injection,guice,Java,Dependency Injection,Guice,最近我对Google Guice进行了一点黑客攻击,我想出了一个主意,根据构造函数声明的类和注释中定义的其他几个参数,向构造函数注入一个字符串。例如: 如果我定义了Guice要使用的新限定符注释@NamedInjectable: @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.FIELD, ElementType.PARAMETER }) @Qualifier public @interface Name

最近我对Google Guice进行了一点黑客攻击,我想出了一个主意,根据构造函数声明的类和注释中定义的其他几个参数,向构造函数注入一个
字符串。例如:
如果我定义了Guice要使用的新限定符注释
@NamedInjectable

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Qualifier
public @interface NamedInjectable
{
    String name() default "";

    boolean indexed() default true;
}
其中name是字符串的新名称基(默认值仅为类的名称),而
索引
说明是否应在每次注入新字符串时递增名称。
e、 g

name
param应指定一个值,如“ 我考虑过使用提供程序绑定或AssistedInject,但我可以做到。失败的一个主要原因是不知何故获得了类的名称


您还有其他想法吗?

没有基于名称定制标准Guice绑定的内置方法。如果您想单独使用Guice,您可能需要

除了标准的@Inject驱动注入之外,Guice还包括用于自定义注入的挂钩。这使Guice能够承载具有自己注入语义或注释的其他框架。大多数开发人员不会直接使用自定义注入;但他们可能会在扩展和第三方库中看到它们的使用。每个自定义注入uires是一个类型侦听器、一个注入侦听器,以及每个类型的注册

Guice的自定义注入文档示例演示了一个使用注入类类型定制的记录器实例,这听起来很像您想要做的事情—从TypeListener中读取您创建的注释的参数不再困难。但是,这不能直接与@InjectAnno一起使用tations或构造函数,因此如果您试图使注入完全在幕后进行,则可能会遇到问题

另一个选项更简单:只需使用工厂并传入新构造的类

public MyClass {
    private final String name;

    @Inject
    public MyClass(NameInjector nameInjector) {
        this.name = nameInjector.get(this, "foo", true);
    }
}

没有基于名称定制标准Guice绑定的内置方法。如果您想单独使用Guice,可能需要

除了标准的@Inject驱动注入之外,Guice还包括用于自定义注入的挂钩。这使Guice能够承载具有自己注入语义或注释的其他框架。大多数开发人员不会直接使用自定义注入;但他们可能会在扩展和第三方库中看到它们的使用。每个自定义注入uires是一个类型侦听器、一个注入侦听器,以及每个类型的注册

Guice的自定义注入文档示例演示了一个使用注入类类型定制的记录器实例,这听起来很像您想要做的事情—从TypeListener中读取您创建的注释的参数不再困难。但是,这不能直接与@InjectAnno一起使用tations或构造函数,因此如果您试图使注入完全在幕后进行,则可能会遇到问题

另一个选项更简单:只需使用工厂并传入新构造的类

public MyClass {
    private final String name;

    @Inject
    public MyClass(NameInjector nameInjector) {
        this.name = nameInjector.get(this, "foo", true);
    }
}

对于普通的GUI注入,您无法访问正在注入某物的类的名称。如果确实需要这样做,则需要使用自定义注入

通过使用自定义
TypeListener
,您可以侦听注入事件并了解正在注入的类。在听到注入事件时,您可以注册一个自定义
MembersInjector
,Guice将在完成自己的注入后调用该自定义
MembersInjector
。此
MembersInjector
可以访问完全构造的insta类的构造函数,因此它可以反映字段和检查注释。但是,它显然不能注入构造函数参数,因为对象已经创建

简而言之,没有办法对构造函数参数进行自定义注入。但是您所描述的想法很可能用于字段注入

如何做

首先,您需要注册一个
TypeListener
(此代码基于链接的Guice wiki页面):

公共类NamedStringListener实现TypeListener{
public void hear(TypeLiteral-TypeLiteral,typeconference-typeconference){
类clazz=typeLiteral.getRawType();
while(clazz!=null){
for(字段:clazz.getDeclaredFields()){
if(field.getType()==String.class&&
field.isAnnotationPresent(NamedInjectable.class)){
Annotation=field.getAnnotation(NamedInjectable.class);
//如何创建和配置此提供程序取决于您。
提供者提供者=新的MyStringProvider(clazz,注解);
注册(新MyMembersInjector(字段,提供程序));
}
}
clazz=clazz.getSuperclass();
}
}
}
然后,在
mymembersinject
中:

公共类MyMembersInjector实现MembersInjector{
最终字段;
最终提供者;
NamedMembersInjector(提供程序){
this.field=字段;
this.provider=提供者;
此.field.setAccessible(true);
}
公众成员(T){
set(t,provider.get());
}
}
我将MyStringProvider的实现留给您


有关更多信息,请参见wiki页面。

对于普通GUI注入,您无法访问正在注入内容的类的名称。如果确实需要这样做,则需要使用自定义注入

通过使用自定义
TypeListener
,您可以侦听注入事件并了解正在注入的类。在听到注入事件时,您可以注册一个自定义
MembersInjector
,Guice将在完成自己的注入后调用该自定义
MembersInjector
public class NamedStringListener implements TypeListener {
    public <T> void hear(TypeLiteral<T> typeLiteral, TypeEncounter<T> typeEncounter) {
        Class<?> clazz = typeLiteral.getRawType();
        while (clazz != null) {
             for (Field field : clazz.getDeclaredFields()) {
             if (field.getType() == String.class &&
                 field.isAnnotationPresent(NamedInjectable.class)) {
                     Annotation annotation = field.getAnnotation(NamedInjectable.class);

                     // How you create and configure this provider is up to you.
                     Provider<String> provider = new MyStringProvider(clazz, annotation);
                     typeEncounter.register(new MyMembersInjector<T>(field, provider));
                 }
             }
         clazz = clazz.getSuperclass();
         }
     }
}
public class MyMembersInjector<T> implements MembersInjector<T> {
    final Field field;
    final Provider<String> provider;

    NamedMembersInjector(Provider<String> provider) {
        this.field = field;
        this.provider = provider;
        this.field.setAccessible(true);
    }

    public void injectMembers(T t) {
         field.set(t, provider.get());
    }
}