Можно ли узнать, кто (какого типа) задал зависимость?

#java #dependency-injection #guice

#java #зависимость-внедрение #guice

Вопрос:

Я использую прослушиватель инъекций, чтобы выполнить инициализацию после введения. Допустим, я создаю эту аннотацию:

 @Retention(RetentionPolicy.RUNTIME)
public static @interface PrintValue {
    String value() default "";
}
  

Теперь я хочу, чтобы каждый раз объект PrintValue класса выводил это значение. Например, если класс такой:

 @PrintValue("Something")
public static class Foo {
}
  

каждый раз, когда вводится Foo, моя инициализация «после введения» заключается в том, чтобы напечатать его значение. Тем не менее, я хочу добавить к этому исключение. Я много чего перепробовал, но мне не удалось этого добиться.

Если класс выглядит так:

 @PrintValue("Something else")
public static class Bar {

    @Inject
    public Bar(Foo foo) {
        System.out.println("Constructed a bar");
    }
}
  

Я не хочу, чтобы инициирование Foo post имело место, потому что объект, который запрашивает foo, является объектом PrintValue класса. Другими словами, это «Что-то другое» «@Переопределяет» PrintValue Foo . Единственный способ, который я могу придумать, чтобы добиться этого, — это попасть в слушателя, класс объекта, который запрашивал зависимость. Посмотрите Полный пример и обратите внимание на комментарий в InjectionListener :

 public class GuiceListener {

    @Retention(RetentionPolicy.RUNTIME)
    public static @interface PrintValue {
        String value() default "";
    }

    @PrintValue("Something")
    public static class Foo {

    }

    @PrintValue("Something else")
    public static class Bar {

        @Inject
        public Bar(Foo foo) {
            System.out.println("Constructed a bar");
        }
    }

    public static void main(String[] args) {
        Module module = new AbstractModule() {
            @Override
            protected void configure() {
                bind(Foo.class);
                bind(Bar.class);
                bindListener(Matchers.any(), new TypeListener() {

                    @Override
                    public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
                        if (type.getRawType().isAnnotationPresent(PrintValue.class)) {
                            encounter.register(new PrintValueInjectionListener());
                        }
                    }

                });
            }
        };
        Injector injector = Guice.createInjector(module);
        Foo foo = injector.getInstance(Foo.class);

        Bar bar = injector.getInstance(Bar.class);
    }

    public static class PrintValueInjectionListener implements InjectionListener<Object> {

        @Override
        public void afterInjection(Object injectee) {
            //get here who asked (its class) the injectee ??
            PrintValue printValue = injectee.getClass().getAnnotation(PrintValue.class);
            System.out.println(printValue.value());
        }

    }
}
  

Если я запускаю это, я получаю в качестве вывода:

 Something
Something
Constructed a bar
Something else
  

Но результат, который я хочу, это:

 Something (printed because of the Foo foo = injector.getInstance(Foo.class))
Constructed a bar
Something else
  

Возможно ли это?

Ответ №1:

Вы можете сделать это с ProvisionListener.getDependencyChain() помощью . Сейчас это устарело, но они приводят несколько примеров замены.