Я разрабатываю расширение, которое предоставляет Injectable bean-компоненту SyntheticBeanBuildItem. Этот компонент используется посредством внедрения конструктора в другой проект, использующий это расширение.
/**
* Bean to inject
*/
@ApplicationScoped
public class FooConfig {
private String url;
private String port;
// Only for CDI injection
@SuppressWarnings("unused")
private FooConfig() {}
public FooConfig(String url, String port) {
this.url = url;
this.port = port;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
}
@Path("")
public class Foo {
private final FooService fooService;
private final FooConfig fooConfig;
public Foo(FooService fooService, FooConfig fooConfig) {
this.fooService = fooService;
this.myConfig = fooConfig;
}
@CheckedTemplate
public static class Templates {
public static native TemplateInstance index();
public static native TemplateInstance list(Uni<List<Bar>> bars, FooConfig fooConfig);
}
@GET
@Produces(MediaType.TEXT_HTML)
public TemplateInstance list() {
return Templates.list(fooService.fetchAsync(), this.fooConfig);
}
}
А вот код расширения, предоставляющий bean-компонент FooConfig:
@Record(ExecutionTime.RUNTIME_INIT)
@BuildStep
public void createConfigBean(List<DevServicesResultBuildItem> devServicesResultBuildItem, FooRecorder recorder, BuildProducer<SyntheticBeanBuildItem> syntheticBeanBuildItemBuildProducer) {
// Retrieve config set Inside FooExtensionProcessor
String apiUrl = devServicesResultBuildItem.stream().filter(devService -> devService.getName().equals(FooServiceContainer.CONTAINER_NAME))
.findFirst()
.orElseThrow(() -> new IllegalStateException("Can't find foo-service url"))
.getConfig().get("url");
syntheticBeanBuildItemBuildProducer.produce(SyntheticBeanBuildItem.configure(FooConfig.class)
.unremovable()
.setRuntimeInit()
.runtimeValue(recorder.createConfig("http://"+apiUrl))
.done());
}
И магнитола:
@Recorder
public class FooServiceRecorder {
public RuntimeValue<FooConfig> createConfig(String url) {
return new RuntimeValue<>(new FooConfig(url, url.split(":")[1]));
}
}
Если я запускаю quarkus dev
внутри проекта, все работает как положено. Боб правильно найден и введен. Если я руну mvn compile
из родительского проекта, опять же все ок.
Но если я запустил mvn package
, плагин Quarkus maven проверит доступность bean-компонента, поэтому я получил эту ошибку:
Suppressed: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.baz.foo.extension.runtime.FooConfig and qualifiers [@Default]
По моему мнению, плагин Quarkus либо не должен пытаться проверять внедрение на этапе пакета, либо учитывать создание bean-компонентов с помощью SyntheticBeanBuildItem.
Я что-то пропустил или это ошибка в плагине?
кажется, что ваш шаг сборки потребляет список DevServicesResultBuildItem
. Однако эти элементы доступны только в режиме разработки, то есть не во время mvn package
. Поэтому я ожидаю, что ваш этап сборки завершится неудачей с IllegalStateException
.
Как выглядит полная трассировка стека?
Я нашел решение. Кажется, плагин Quarkus Maven проверяет доступность bean-компонентов на этапе пакета, поэтому мне нужно сделать bean-компонент моего расширения доступным через Jandex, при этом плагин maven jandex применяется во время выполнения pom.xml моего расширения.
Поскольку мое расширение также предоставляет этот компонент с помощью SyntheticBeanBuildItem, мне пришлось исключить компонент с помощью EcludedTypeBuildItem, иначе я получу неоднозначную зависимость.
Это кажется немного сложным, но это работает
Не совсем ответ, но если вы регистрируете
FooConfig
как синтетический bean-компонент, аннотация@ApplicationScoped
будет игнорироваться. Вам следует удалить его и определить область действия с помощью конфигуратора компонента.