Создание пользовательской аннотации @Inject

Я использую lombok в своем проекте с большим количеством классов с @RequiredArgsConstructors. Я бы хотел, чтобы эти конструкторы автоматически использовались в guice.

Один из вариантов, который работает, — это использовать @RequiredArgsConstructors(onConstructor=@__(@Inject)), но это и уродливо, и экспериментально (читай: скорее всего исчезнет с ломбока в будущем).

Что я думаю сделать, так это создать пользовательскую аннотацию для инъекции, скажем, @InjectOnlyConstructor, чтобы поместить определение моего класса и использовать SPI guices для привязки этих типов. Но я не могу понять, как обнаружить эти типы в SPI.

Как я могу просматривать элементы guice и привязываться к этим конструкторам, которые guice по умолчанию отклоняет?

Пример того, как я хочу, чтобы класс выглядел:

@Singleton
@InjectOnlyConstructor
@RequiredArgsConstructor
public class CatPictureService {
    private final WebServiceClient client;

    // Cool stuff that would make facebook cry
}

В качестве резервного плана у меня может быть модуль, который сканирует пакеты моего проекта и автоматически связывает эти типы.


person Michael Deardeuff    schedule 01.10.2015    source источник
comment
Хитрость будет заключаться в использовании toConstructor() привязки. Я напишу более полное решение позже!   -  person Tavian Barnes    schedule 02.10.2015
comment
@TavianBarnes Да! Я полагал, что это способ сделать серверную часть, но понял, что передняя часть обнаруживает типы, которые необходимо связать с помощью SPI (т.е. за исключением сканирования пути к классам).   -  person Michael Deardeuff    schedule 02.10.2015
comment
Tangential: аннотации к конструкторам, методам и параметрам требуются не только для внедрения зависимостей, но и для различных других вариантов использования. Учитывая, что статус функции Lombok onX «неизвестен», я ищу более полный пример, который работает не только для Guice, но и для других. У вас есть какое-нибудь решение?   -  person Manu Manjunath    schedule 22.10.2015


Ответы (1)


Я начинаю думать, что невозможно подключиться к Guice для разрешения несвязанных типов.

Поэтому я придумал четыре разных решения. Первый мне больше всего нравится, он включает в себя кажущийся шаблон явной проводки, который используют официальные расширения Guice. Вы используете его следующим образом:

public class Bar {
    private Bar(XYZ xyz) { ... }
}

Injector inject = Guice.createInjector(new AbstractModule() {
    protected void configure() {
        install(new OnlyConstructorBuilder(Bar.class));
    }
});

OnlyConstructorBuilder определяется как таковой:

@RequiredArgsConstructor
private static class OnlyConstructorBuilder extends AbstractModule {
    private final Class<?> type;

    @Override
    protected void configure() {
        bindToOnlyConstructor(type);
    }

    @SuppressWarnings("unchecked")
    private <T> void bindToOnlyConstructor(Class<T> type) {
        Constructor<T>[] ctors = (Constructor<T>[])type.getDeclaredConstructors();

        if (ctors.length > 1) {
            addError("%s has too many constructors %s", type.getName(), Arrays.toString(ctors));
            return;
        } else if (ctors.length < 1) {
            addError("%s needs at least one constructor", type.getName());
            return;
        } else {
            bind(type).toConstructor(ctors[0]);
        }
    }
}

Второй подход заключается в просмотре пути к классу или его части в поисках определенной аннотации. Это была моя первоначальная идея, и это не так уж сложно, если вы используете вспомогательные средства отражения Guava. Я делал что-то подобное раньше, но люди находят это слишком волшебным. Обязательная часть аналогична приведенной выше.

Третий подход заключается в использовании bind(Bar.class) в модуле и использовании Elements SPI для поиска UntargetedBinding с определенной аннотацией. Но поскольку я уже привязываю класс, я мог бы также привязать его к единственному конструктору.

Четвертый подход как раз самый худший. Он использует Elements API и определяет зависимости каждой привязки; поиск несвязанных зависимостей с определенной аннотацией. Это дорога, по которой я не хочу идти.

person Michael Deardeuff    schedule 07.10.2015
comment
В классе configure класса Module сканирование частей пути к классу (скажем, с использованием библиотеки Reflections) и связывание их, как bindToOnlyConstructor, кажется мне самым чистым решением. - person Manu Manjunath; 03.06.2016