I try to use latest Qarkus configuration tool : @ConfigMapping so I defined a GreetingConfig object:
@ConfigMapping(prefix = "org.acme.greeting")
public interface GreetingConfig {
String prefix();
}
That config is injected in a CDI Singleton :
@Singleton
public class GreetingService {
@Inject GreetingConfig config;
public String greet(String user) {
return config.prefix().concat(" - Hello ").concat(user).concat(" !!");
}
}
The singleton is injected in a JAX-RS Filter and in a JAX-RS Resource
@Provider
public class GreetingFilter implements ContainerRequestFilter {
private static final Logger LOGGER = Logger.getLogger(GreetingFilter.class.getName());
@Inject GreetingService service;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
LOGGER.log(Level.INFO, service.greet("Quarkus"));
}
}
@Path("/hello")
public class GreetingResource {
@Inject GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello(@QueryParam("user") @DefaultValue("Quarkus") String user) {
return service.greet(user);
}
}
The application.properties file contains also :
org.acme.greeting.prefix=ACME Greetings
Application crash at startup :
java.lang.RuntimeException: java.lang.ExceptionInInitializerError
at io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:712)
at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:785)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.api.extension.InvocationInterceptor.interceptTestClassConstructor(InvocationInterceptor.java:72)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:77)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestClassConstructor(ClassBasedTestDescriptor.java:342)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateTestClass(ClassBasedTestDescriptor.java:289)
at org.junit.jupiter.engine.descriptor.ClassTestDescriptor.instantiateTestClass(ClassTestDescriptor.java:79)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:267)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:259)
at java.base/java.util.Optional.orElseGet(Optional.java:369)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:258)
at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:31)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:101)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:100)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:65)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:111)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:111)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:79)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ExceptionInInitializerError
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at io.quarkus.runner.bootstrap.StartupActionImpl.run(StartupActionImpl.java:165)
at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:380)
at io.quarkus.test.junit.QuarkusTestExtension.ensureStarted(QuarkusTestExtension.java:680)
at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:727)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeBeforeAllCallbacks$8(ClassBasedTestDescriptor.java:368)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeBeforeAllCallbacks(ClassBasedTestDescriptor.java:368)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:192)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.before(ClassBasedTestDescriptor.java:78)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:136)
... 31 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:225)
... 43 more
Caused by: java.lang.RuntimeException: Error injecting org.acme.GreetingService org.acme.api.filter.GreetingFilter.service
at org.acme.api.filter.GreetingFilter_Bean.create(GreetingFilter_Bean.zig:148)
at org.acme.api.filter.GreetingFilter_Bean.create(GreetingFilter_Bean.zig:171)
at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:96)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
at org.acme.api.filter.GreetingFilter_Bean.get(GreetingFilter_Bean.zig:203)
at org.acme.api.filter.GreetingFilter_Bean.get(GreetingFilter_Bean.zig:219)
at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:433)
at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:446)
at io.quarkus.arc.impl.ArcContainerImpl$1.get(ArcContainerImpl.java:269)
at io.quarkus.arc.impl.ArcContainerImpl$1.get(ArcContainerImpl.java:266)
at io.quarkus.resteasy.common.runtime.QuarkusConstructorInjector.construct(QuarkusConstructorInjector.java:39)
at org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl.injectedInstance(ResteasyProviderFactoryImpl.java:1399)
at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$AbstractInterceptorFactory.createInterceptor(JaxrsInterceptorRegistryImpl.java:150)
at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.initialize(JaxrsInterceptorRegistryImpl.java:168)
at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.checkInitialize(JaxrsInterceptorRegistryImpl.java:183)
at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$OnDemandInterceptorFactory.getInterceptor(JaxrsInterceptorRegistryImpl.java:193)
at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl$AbstractInterceptorFactory.postMatch(JaxrsInterceptorRegistryImpl.java:131)
at org.jboss.resteasy.core.interception.jaxrs.JaxrsInterceptorRegistryImpl.postMatch(JaxrsInterceptorRegistryImpl.java:288)
at org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl.postMatch(ContainerRequestFilterRegistryImpl.java:30)
at org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl.postMatch(ContainerRequestFilterRegistryImpl.java:12)
at org.jboss.resteasy.core.ResourceMethodInvoker.<init>(ResourceMethodInvoker.java:142)
at org.jboss.resteasy.core.ResourceMethodRegistry.processMethod(ResourceMethodRegistry.java:381)
at org.jboss.resteasy.core.ResourceMethodRegistry.register(ResourceMethodRegistry.java:308)
at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:259)
at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:227)
at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:208)
at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:192)
at org.jboss.resteasy.core.ResourceMethodRegistry.addResourceFactory(ResourceMethodRegistry.java:175)
at org.jboss.resteasy.core.ResourceMethodRegistry.addPerRequestResource(ResourceMethodRegistry.java:87)
at org.jboss.resteasy.core.ResteasyDeploymentImpl.registerResources(ResteasyDeploymentImpl.java:518)
at org.jboss.resteasy.core.ResteasyDeploymentImpl.registration(ResteasyDeploymentImpl.java:475)
at org.jboss.resteasy.core.ResteasyDeploymentImpl.startInternal(ResteasyDeploymentImpl.java:164)
at org.jboss.resteasy.core.ResteasyDeploymentImpl.start(ResteasyDeploymentImpl.java:121)
at io.quarkus.resteasy.runtime.standalone.ResteasyStandaloneRecorder.staticInit(ResteasyStandaloneRecorder.java:37)
at io.quarkus.deployment.steps.ResteasyStandaloneBuildStep$staticInit-210558872.deploy_0(ResteasyStandaloneBuildStep$staticInit-210558872.zig:897)
at io.quarkus.deployment.steps.ResteasyStandaloneBuildStep$staticInit-210558872.deploy(ResteasyStandaloneBuildStep$staticInit-210558872.zig:40)
at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:205)
... 43 more
Caused by: java.lang.RuntimeException: Error injecting org.acme.config.GreetingConfig org.acme.GreetingService.config
at org.acme.GreetingService_Bean.create(GreetingService_Bean.zig:199)
at org.acme.GreetingService_Bean.create(GreetingService_Bean.zig:222)
at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:96)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:29)
at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:26)
at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:26)
at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:26)
at org.acme.GreetingService_Bean.get(GreetingService_Bean.zig:254)
at org.acme.GreetingService_Bean.get(GreetingService_Bean.zig:270)
at org.acme.api.filter.GreetingFilter_Bean.create(GreetingFilter_Bean.zig:131)
... 83 more
Caused by: java.util.NoSuchElementException: SRCFG00027: Could not find a mapping for org.acme.config.GreetingConfig
at io.smallrye.config.ConfigMappings.getConfigMapping(ConfigMappings.java:73)
at io.smallrye.config.SmallRyeConfig.getConfigMapping(SmallRyeConfig.java:423)
at io.quarkus.arc.runtime.ConfigMappingCreator.create(ConfigMappingCreator.java:28)
at org.acme.config.GreetingConfig_04302c935a6cb43e5f29ca4271833ab99b620b3b_Synthetic_Bean.create(GreetingConfig_04302c935a6cb43e5f29ca4271833ab99b620b3b_Synthetic_Bean.zig:128)
at org.acme.config.GreetingConfig_04302c935a6cb43e5f29ca4271833ab99b620b3b_Synthetic_Bean.get(GreetingConfig_04302c935a6cb43e5f29ca4271833ab99b620b3b_Synthetic_Bean.zig:159)
at org.acme.config.GreetingConfig_04302c935a6cb43e5f29ca4271833ab99b620b3b_Synthetic_Bean.get(GreetingConfig_04302c935a6cb43e5f29ca4271833ab99b620b3b_Synthetic_Bean.zig:182)
at io.quarkus.arc.impl.CurrentInjectionPointProvider.get(CurrentInjectionPointProvider.java:52)
at org.acme.GreetingService_Bean.create(GreetingService_Bean.zig:182)
... 93 more
Injection in the JAR-RS resource works whatever bean type the service is (@ApplicationScope nor @Singleton) but in the Filter, only @ApplicationScope bean can be injected avoiding the runtime exception...
Is it a bug or is it normal that we cannot inject a pseudo scope bean with config mapping in a JAX-RS @Provider (Filter or BodyWritter) ?
Unfortunately, it's not a bug. It's a feature of jax-rs :-)
A solution is to put your service into the Instance class.
@Inject Instance<GreetingService> service;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
LOGGER.log(Level.INFO, service.get().greet("Quarkus"));
}
It delegates injection to the later phase (a kind of lazy injection during runtime).
I have found more info here https://javaee.github.io/javaee-spec/javadocs/javax/enterprise/inject/Instance.html
Based on Marek answer (thanks for the solution ;-)) there is also an option to use the Instance based injection on the config object in the Service Bean and to keep a classic injection in the Provider...
Maybe it's a better design approach to let the bean aware of it's config injection and to deal with the Instance object itself, by the way, initial idea is the same, avoiding runtime problem whereas config object is not available at Provider instanciation time by using an Instance.
@Singleton
public class GreetingService {
@Inject Instance<GreetingConfig> config;
public String greet(String user) {
return config.get().prefix().concat(" - Hello ").concat(user).concat(" !!");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With