Search code examples
javainversion-of-controlguiceinject

Guice dynamic inject with custom annotation


I have some resource, but I can not iterator it and bind them all, I have to use the key to request the resource.So, I have to dynamic inject.

I define an annotation like

@Target({ METHOD, CONSTRUCTOR, FIELD })
@Retention(RUNTIME)
@Documented
@BindingAnnotation
public @interface Res
{
    String value();// the key of the resource
}

use like this

public class Test
{
    @Inject
    @Res("author.name")
    String name;
    @Inject
    @Res("author.age")
    int age;
    @Inject
    @Res("author.blog")
    Uri blog;
}

I have to handle the injection annotated by @Res and I need to know the inject field and the annotation.

Is this possible in Guice and how ? even with spi ?


Solution

  • I work out follow CustomInjections

    Code like this

    public class PropsModule extends AbstractModule
    {
        private final Props props;
        private final InProps inProps;
    
        private PropsModule(Props props)
        {
            this.props = props;
            this.inProps = InProps.in(props);
        }
    
        public static PropsModule of(Props props)
        {
            return new PropsModule(props);
        }
    
        @Override
        protected void configure()
        {
            bindListener(Matchers.any(), new TypeListener()
            {
                @Override
                public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter)
                {
                    Class<? super I> clazz = type.getRawType();
                    if (!clazz.isAnnotationPresent(WithProp.class))
                        return;
                    for (Field field : clazz.getDeclaredFields())
                    {
                        Prop prop = field.getAnnotation(Prop.class);
                        if (prop == null)
                            continue;
    
                        encounter.register(new PropInjector<I>(prop, field));
                    }
                }
            });
        }
    
        class PropInjector<T> implements MembersInjector<T>
        {
            private final Prop prop;
            private final Field field;
    
            PropInjector(Prop prop, Field field)
            {
                this.prop = prop;
                this.field = field;
                field.setAccessible(true);
            }
    
            @Override
            public void injectMembers(T instance)
            {
                try {
                    Class<?> targetType = field.getType();
                    Object val = inProps.as(prop.value(), targetType);
                    field.set(instance, val);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }