Внедрение конструктора с CDI + Weld

Я хочу использовать Constructor Injection, поскольку это делает мои модульные тесты более безопасными и легкими для написания: я не могу забыть установить поля для инъекции. CDI поддерживает это, и javadoc аннотации @Inject говорит: «@Inject не является обязательным для общедоступных конструкторов без аргументов, когда нет других конструкторов. Это позволяет инжекторам вызывать конструкторы по умолчанию».

Я понимаю, что для других стандартов требуется конструктор без аргументов (например, JAX-RS; см. этот вопрос), что облом. Но даже для такого простого класса, как:

public class Bar {
    private final Foo foo;

    public Bar(Foo foo) {
        this.foo = foo;
    }
}

Weld терпит неудачу, говоря: DeploymentException: WELD-001408: Unsatisfied dependencies for type Bar. Когда добавляю аннотацию @Inject, работает.

Я действительно не ожидаю больше никаких ошибок в Weld, так как он хорошо зарекомендовал себя в течение многих лет; Я, наверное, что-то не так понял. Но, возможно, это ускользнуло от внимания только потому, что сообщество Jakarta EE просто не выполняет никаких инъекций конструктора.


person rü-    schedule 27.01.2020    source источник
comment
Не знаете, в чем именно проблема? Как сказано в спецификации, вам не нужно добавлять аннотацию @Inject , если есть открытый конструктор без аргументов (неявный или явный) без других конструкторов. У вас есть конструктор с одним аргументом, поэтому вам нужно добавить аннотацию @Inject к этому конструктору. Если вам также нужен конструктор без аргументов, вы также можете добавить его, но, возможно, вам придется отказаться от foo final.   -  person Slaw    schedule 27.01.2020
comment
@Slaw Я создал минималистичный демонстрационный проект на GitHub. Boundary вводит Bar, который вводит Foo. Прекрасно работает с @Inject в строке 8 Bar. Когда я удаляю эту аннотацию, Велд жалуется: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Неудовлетворенные зависимости для типа Bar с квалификаторами @Default в точке внедрения [UnbackedAnnotatedField] @Inject demo.Boundary.bar.   -  person rü-    schedule 27.01.2020
comment
Просто для пояснения, поскольку вы уже приняли ответ: у вас нет конструктора без аргументов, что означает, что требуется аннотация @Inject, как указано в указанной вами спецификации.   -  person Slaw    schedule 28.01.2020
comment
Точно ... Я перечитал это, так как это противоречит интуиции. Я думал, что это требуется только тогда, когда есть несколько конструкторов для устранения неоднозначности. Спасибо!   -  person rü-    schedule 28.01.2020
comment
Я бы сказал, что это не противоречит интуиции. Подумайте об этом так: наличие единственного конструктора без аргументов - это особый случай. В Java, если класс не объявляет конструктор, неявно добавляется конструктор без аргументов по умолчанию. Было бы неприятно объявлять конструктор без аргументов, без специальной логики, чтобы просто добавить аннотацию @Inject. Если вы объявляете конструктор без аргументов, и это единственный конструктор, вам не нужно добавлять @Inject, потому что нет видимой снаружи разницы между этим конструктором и конструктором по умолчанию.   -  person Slaw    schedule 28.01.2020
comment
Если у вас более одного конструктора, вам нужно явно указать, какой конструктор будет использоваться. Если у вас есть только один конструктор, но у этого конструктора есть аргументы, вам также нужно добавить @Inject; он явно помечает конструктор как поддерживающий CDI и, таким образом, позволяет вам контролировать, может ли компонент быть создан контейнером CDI. Другими словами, вы всегда должны добавлять аннотацию @Inject с одним исключением - (фактически) конструкторами по умолчанию.   -  person Slaw    schedule 28.01.2020
comment
только конструктор по умолчанию = ›без внедрения конструктора. несколько конструкторов = ›используйте @Inject, чтобы отметить тот, который будет использоваться. Мы согласны с этим. Но когда у меня есть только один (не используемый по умолчанию) конструктор, я думаю, CDI может это принять: все остальное в моих глазах не имело бы никакого смысла. Я считаю, что стандарт здесь слишком консервативен. Но у меня есть рассуждения. Спасибо!   -  person rü-    schedule 29.01.2020


Ответы (1)


Это не ошибка Weld. Как указано в спецификации, вам понадобится @javax.inject.Inject на вашем конструктор. Единственный раз, когда он вам не нужен, - это когда у вас есть конструктор с нулевым аргументом, и вы не хотите, чтобы какой-либо другой конструктор вызывался контейнером.

person Laird Nelson    schedule 27.01.2020
comment
Ты прав. Это сбивает с толку и ограничивает, но это то, как это указано. - person rü-; 27.01.2020