This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git
The following commit(s) were added to refs/heads/master by this push:
new f8862de Type safe component injection
f8862de is described below
commit f8862de6e48ee41eddc5d3dec84d72b61e2f6895
Author: lburgazzoli <[email protected]>
AuthorDate: Thu Jun 18 12:17:06 2020 +0200
Type safe component injection
This allows to:
```java
@ApplicationScoped
public static class Configurer {
@Inject
LogComponent log;
@PostConstruct
void setUpLogComponent() {
log.setBasicPropertyBinding(true);
log.setExchangeFormatter(new MyExchangeFormatter());
}
public LogComponent getLog() {
return log;
}
}
@ApplicationScoped
public static class Holder {
private LogComponent log;
@Inject
public Holder(LogComponent log) {
this.log = log;
}
public LogComponent getLog() {
return log;
}
}
```
---
.../core/deployment/InjectionPointsProcessor.java | 124 +++++++++++++++++++++
.../core/runtime/CamelInjectionPointTest.java | 91 +++++++++++++++
.../quarkus/core/InjectionPointsRecorder.java | 47 ++++++++
3 files changed, 262 insertions(+)
diff --git
a/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java
new file mode 100644
index 0000000..79f7b20
--- /dev/null
+++
b/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/InjectionPointsProcessor.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.core.deployment;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem;
+import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
+import io.quarkus.arc.processor.BuildExtension;
+import io.quarkus.arc.processor.InjectionPointInfo;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import org.apache.camel.Component;
+import org.apache.camel.quarkus.core.InjectionPointsRecorder;
+import org.jboss.jandex.AnnotationInstance;
+import org.jboss.jandex.AnnotationTarget;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.FieldInfo;
+import org.jboss.jandex.MethodInfo;
+import org.jboss.jandex.Type;
+import org.jboss.logging.Logger;
+
+public class InjectionPointsProcessor {
+ private static final Logger LOGGER =
Logger.getLogger(InjectionPointsProcessor.class);
+
+ private static final DotName ANNOTATION_NAME_NAMED = DotName.createSimple(
+ Named.class.getName());
+ private static final DotName INTERFACE_NAME_COMPONENT =
DotName.createSimple(
+ Component.class.getName());
+
+ private static SyntheticBeanBuildItem syntheticBean(DotName name,
Supplier<?> creator) {
+ return SyntheticBeanBuildItem.configure(name)
+ .supplier(creator)
+ .scope(Singleton.class)
+ .unremovable()
+ .setRuntimeInit()
+ .done();
+ }
+
+ @Record(ExecutionTime.RUNTIME_INIT)
+ @BuildStep
+ BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem
injectedComponents(
+ CombinedIndexBuildItem index,
+ InjectionPointsRecorder recorder,
+ BeanRegistrationPhaseBuildItem beanRegistrationPhase,
+ BuildProducer<SyntheticBeanBuildItem> syntheticBeans) {
+
+ final Collection<ClassInfo> components =
index.getIndex().getAllKnownImplementors(INTERFACE_NAME_COMPONENT);
+ final Set<String> created = new HashSet<>();
+
+ for (InjectionPointInfo injectionPoint :
beanRegistrationPhase.getContext().get(BuildExtension.Key.INJECTION_POINTS)) {
+ if (injectionPoint.getTarget().kind() ==
AnnotationTarget.Kind.FIELD) {
+ FieldInfo target = injectionPoint.getTarget().asField();
+
+ if (!created.add(target.type().name().toString())) {
+ continue;
+ }
+
+ if (components.stream().anyMatch(ci ->
Objects.equals(ci.name(), target.type().name()))) {
+ final AnnotationInstance named =
target.annotation(ANNOTATION_NAME_NAMED);
+ final String componentName = named == null ? target.name()
: named.value().asString();
+ final Supplier<?> creator =
recorder.componentSupplier(componentName, target.type().toString());
+
+ LOGGER.debugf("Creating synthetic component bean [name=%s,
type=%s]", componentName, target.type().name());
+
+ syntheticBeans.produce(syntheticBean(target.type().name(),
creator));
+ }
+ }
+
+ if (injectionPoint.getTarget().kind() ==
AnnotationTarget.Kind.METHOD) {
+ final MethodInfo target =
injectionPoint.getTarget().asMethod();
+ final List<Type> types = target.parameters();
+
+ for (int i = 0; i < types.size(); i++) {
+ Type type = types.get(0);
+
+ if (!created.add(type.name().toString())) {
+ continue;
+ }
+
+ if (components.stream().anyMatch(ci ->
Objects.equals(ci.name(), type.name()))) {
+ final AnnotationInstance named =
target.annotation(ANNOTATION_NAME_NAMED);
+ final String componentName = named == null ?
target.parameterName(i) : named.value().asString();
+ final Supplier<?> creator =
recorder.componentSupplier(componentName, type.toString());
+
+ LOGGER.debugf("Creating synthetic component bean
[name=%s, type=%s]", componentName, type.name());
+
+ syntheticBeans.produce(syntheticBean(type.name(),
creator));
+ }
+ }
+ }
+ }
+
+ // method using BeanRegistrationPhaseBuildItem should return a
BeanConfiguratorBuildItem
+ // otherwise the build step may be processed at the wrong time.
+ return new BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem();
+ }
+}
diff --git
a/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelInjectionPointTest.java
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelInjectionPointTest.java
new file mode 100644
index 0000000..597c24f
--- /dev/null
+++
b/extensions-core/core/deployment/src/test/java/org/apache/camel/quarkus/core/runtime/CamelInjectionPointTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.core.runtime;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import io.quarkus.test.QuarkusUnitTest;
+import org.apache.camel.Exchange;
+import org.apache.camel.component.log.LogComponent;
+import org.apache.camel.spi.ExchangeFormatter;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.spec.JavaArchive;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class CamelInjectionPointTest {
+ @RegisterExtension
+ static final QuarkusUnitTest CONFIG = new QuarkusUnitTest()
+ .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class)
+ .addClasses(Configurer.class, MyExchangeFormatter.class));
+
+ @Inject
+ Configurer configurer;
+ @Inject
+ Holder holder;
+
+ @Test
+ public void testConfigurer() {
+ assertThat(configurer.getLog()).isNotNull();
+ assertThat(configurer.getLog().isBasicPropertyBinding()).isTrue();
+
assertThat(configurer.getLog().getExchangeFormatter()).isInstanceOf(MyExchangeFormatter.class);
+ assertThat(holder.getLog()).isNotNull();
+ assertThat(holder.getLog().isBasicPropertyBinding()).isTrue();
+
assertThat(holder.getLog().getExchangeFormatter()).isInstanceOf(MyExchangeFormatter.class);
+ }
+
+ @ApplicationScoped
+ public static class Configurer {
+ @Inject
+ LogComponent log;
+
+ @PostConstruct
+ void setUpLogComponent() {
+ log.setBasicPropertyBinding(true);
+ log.setExchangeFormatter(new MyExchangeFormatter());
+ }
+
+ public LogComponent getLog() {
+ return log;
+ }
+ }
+
+ @ApplicationScoped
+ public static class Holder {
+ private LogComponent log;
+
+ @Inject
+ public Holder(LogComponent log) {
+ this.log = log;
+ }
+
+ public LogComponent getLog() {
+ return log;
+ }
+ }
+
+ public static class MyExchangeFormatter implements ExchangeFormatter {
+ @Override
+ public String format(Exchange exchange) {
+ return exchange.toString();
+ }
+ }
+}
diff --git
a/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/InjectionPointsRecorder.java
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/InjectionPointsRecorder.java
new file mode 100644
index 0000000..c281fad
--- /dev/null
+++
b/extensions-core/core/runtime/src/main/java/org/apache/camel/quarkus/core/InjectionPointsRecorder.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.core;
+
+import java.util.function.Supplier;
+
+import io.quarkus.arc.Arc;
+import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Component;
+
+@Recorder
+public class InjectionPointsRecorder {
+ public Supplier<? extends Component> componentSupplier(String
componentName, String componentType) {
+ return new Supplier<Component>() {
+ @Override
+ public Component get() {
+ // We can't inject the CamelContext from the BuildStep as it
will create a
+ // dependency cycle as the BuildStep that creates the
CamelContext requires
+ // BeanManger instance. As this is a fairly trivial job, we
can safely keep
+ // the context lookup-at runtime.
+ final CamelContext camelContext =
Arc.container().instance(CamelContext.class).get();
+ if (camelContext == null) {
+ throw new IllegalStateException("No CamelContext found");
+ }
+
+ return camelContext.getComponent(
+ componentName,
+
camelContext.getClassResolver().resolveClass(componentType, Component.class));
+ }
+ };
+ }
+}