This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch lessjars in repository https://gitbox.apache.org/repos/asf/camel.git
commit 00ff3b0eeccc12f9d1a564fbdc656c59c3f47c63 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Thu May 29 15:54:27 2025 +0200 CAMEL-22119: camel-jbang: Reduce number of JARs for SB/Q annotation based dependency injection --- .../converter/AnnotationTypeConverterLoader.java | 5 +- .../scan/AnnotatedWithAnyPackageScanFilter.java | 4 +- .../scan/AnnotatedWithPackageScanFilter.java | 4 +- .../org/apache/camel/util/AnnotationHelper.java | 233 +++++++++++++++++++++ .../java/org/apache/camel/util/ObjectHelper.java | 66 +++--- .../{MyPojo.java => AnnotationHelperTest.java} | 23 +- .../test/java/org/apache/camel/util/MyPojo.java | 3 + dsl/camel-kamelet-main/pom.xml | 19 +- .../download/BasePackageScanDownloadListener.java | 30 ++- .../injection/AnnotationDependencyInjection.java | 104 ++++----- .../main/AnnotationDependencyInjectionTest.java | 55 +++++ .../apache/camel/main/app/MyNoValueSpringBean.java | 14 +- .../org/apache/camel/main/app/MySpringBean.java | 21 +- 13 files changed, 432 insertions(+), 149 deletions(-) diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java b/core/camel-base/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java index 34b026ee6e0..542a0db2faf 100644 --- a/core/camel-base/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java +++ b/core/camel-base/src/main/java/org/apache/camel/impl/converter/AnnotationTypeConverterLoader.java @@ -38,6 +38,7 @@ import org.apache.camel.TypeConverterLoaderException; import org.apache.camel.spi.PackageScanClassResolver; import org.apache.camel.spi.TypeConverterLoader; import org.apache.camel.spi.TypeConverterRegistry; +import org.apache.camel.util.AnnotationHelper; import org.apache.camel.util.CastUtils; import org.apache.camel.util.IOHelper; import org.apache.camel.util.ObjectHelper; @@ -280,7 +281,7 @@ public class AnnotationTypeConverterLoader implements TypeConverterLoader { for (Method method : methods) { // this may be prone to ClassLoader or packaging problems when the same class is defined // in two different jars (as is the case sometimes with specs). - if (ObjectHelper.hasAnnotation(method, Converter.class, true)) { + if (AnnotationHelper.hasAnnotation(method, Converter.class, true)) { boolean allowNull = false; if (method.getAnnotation(Converter.class) != null) { allowNull = method.getAnnotation(Converter.class).allowNull(); @@ -301,7 +302,7 @@ public class AnnotationTypeConverterLoader implements TypeConverterLoader { } catch (NoClassDefFoundError e) { boolean ignore = false; // does the class allow to ignore the type converter when having load errors - if (ObjectHelper.hasAnnotation(type, Converter.class, true)) { + if (AnnotationHelper.hasAnnotation(type, Converter.class, true)) { if (type.getAnnotation(Converter.class) != null) { ignore = type.getAnnotation(Converter.class).ignoreOnLoadError(); } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithAnyPackageScanFilter.java b/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithAnyPackageScanFilter.java index 0f66b8b519d..d05e1c2fde6 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithAnyPackageScanFilter.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithAnyPackageScanFilter.java @@ -20,7 +20,7 @@ import java.lang.annotation.Annotation; import java.util.Set; import org.apache.camel.spi.PackageScanFilter; -import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.AnnotationHelper; /** * Package scan filter for testing if a given class is annotated with any of the annotations. @@ -45,7 +45,7 @@ public class AnnotatedWithAnyPackageScanFilter implements PackageScanFilter { return false; } for (Class<? extends Annotation> annotation : annotations) { - if (ObjectHelper.hasAnnotation(type, annotation, checkMetaAnnotations)) { + if (AnnotationHelper.hasAnnotation(type, annotation, checkMetaAnnotations)) { return true; } } diff --git a/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithPackageScanFilter.java b/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithPackageScanFilter.java index b4d51ee5a37..024de75f242 100644 --- a/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithPackageScanFilter.java +++ b/core/camel-support/src/main/java/org/apache/camel/support/scan/AnnotatedWithPackageScanFilter.java @@ -19,7 +19,7 @@ package org.apache.camel.support.scan; import java.lang.annotation.Annotation; import org.apache.camel.spi.PackageScanFilter; -import org.apache.camel.util.ObjectHelper; +import org.apache.camel.util.AnnotationHelper; /** * Package scan filter for testing if a given class is annotated with a certain annotation. @@ -40,7 +40,7 @@ public class AnnotatedWithPackageScanFilter implements PackageScanFilter { @Override public boolean matches(Class<?> type) { - return type != null && ObjectHelper.hasAnnotation(type, annotation, checkMetaAnnotations); + return type != null && AnnotationHelper.hasAnnotation(type, annotation, checkMetaAnnotations); } public Class<? extends Annotation> getAnnotation() { diff --git a/core/camel-util/src/main/java/org/apache/camel/util/AnnotationHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/AnnotationHelper.java new file mode 100644 index 00000000000..b6738c5af1d --- /dev/null +++ b/core/camel-util/src/main/java/org/apache/camel/util/AnnotationHelper.java @@ -0,0 +1,233 @@ +/* + * 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.util; + +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public final class AnnotationHelper { + + /** + * Returns a list of methods which are annotated with the given annotation + * + * @param type the type to reflect on + * @param annotationType the annotation type + * @return a list of the methods found + */ + public static List<Method> findMethodsWithAnnotation( + Class<?> type, + Class<? extends Annotation> annotationType) { + return findMethodsWithAnnotation(type, annotationType, false); + } + + /** + * Returns a list of methods which are annotated with the given annotation + * + * @param type the type to reflect on + * @param annotationType the annotation type + * @param checkMetaAnnotations check for meta annotations + * @return a list of the methods found + */ + public static List<Method> findMethodsWithAnnotation( + Class<?> type, + Class<? extends Annotation> annotationType, + boolean checkMetaAnnotations) { + List<Method> answer = new ArrayList<>(); + do { + Method[] methods = type.getDeclaredMethods(); + for (Method method : methods) { + if (hasAnnotation(method, annotationType, checkMetaAnnotations)) { + answer.add(method); + } + } + type = type.getSuperclass(); + } while (type != null); + return answer; + } + + /** + * Checks if a Class or Method are annotated with the given annotation + * + * @param elem the Class or Method to reflect on + * @param annotationType the annotation type + * @param checkMetaAnnotations check for meta annotations + * @return true if annotations is present + */ + public static boolean hasAnnotation( + AnnotatedElement elem, Class<? extends Annotation> annotationType, + boolean checkMetaAnnotations) { + if (elem.isAnnotationPresent(annotationType)) { + return true; + } + if (checkMetaAnnotations) { + for (Annotation a : elem.getAnnotations()) { + for (Annotation meta : a.annotationType().getAnnotations()) { + if (meta.annotationType().getName().equals(annotationType.getName())) { + return true; + } + } + } + } + return false; + } + + /** + * Checks if the class has been annotated with the given annotation (FQN class name) and if present, then returns + * the value attribute. + * + * @param clazz the class + * @param fqnAnnotationName the FQN of the annotation + * @return null if not annotated, otherwise the value, an empty string means annotation but has no + * value + */ + public static String getAnnotationValue(Class<?> clazz, String fqnAnnotationName) { + for (Annotation ann : clazz.getAnnotations()) { + if (ann.annotationType().getName().equals(fqnAnnotationName)) { + String s = ann.toString(); + return StringHelper.between(s, "\"", "\""); + } + } + return null; + } + + /** + * Checks if the class has been annotated with the given annotation (FQN class name). + * + * @param clazz the class + * @param fqnAnnotationName the FQN of the annotation + * @return true if annotated or false if not + */ + public static boolean hasAnnotation(Class<?> clazz, String fqnAnnotationName) { + for (Annotation ann : clazz.getAnnotations()) { + if (ann.annotationType().getName().equals(fqnAnnotationName)) { + return true; + } + } + return false; + } + + /** + * Checks if the method has been annotated with the given annotation (FQN class name). + * + * @param method the method + * @param fqnAnnotationName the FQN of the annotation + * @return true if annotated or false if not + */ + public static boolean hasAnnotation(Method method, String fqnAnnotationName) { + for (Annotation ann : method.getAnnotations()) { + if (ann.annotationType().getName().equals(fqnAnnotationName)) { + return true; + } + } + return false; + } + + /** + * Checks if the method has been annotated with the given annotation (FQN class name) and if present, then returns + * the value attribute. + * + * @param method the method + * @param fqnAnnotationName the FQN of the annotation + * @return null if not annotated, otherwise the value, an empty string means annotation but has no + * value + */ + public static String getAnnotationValue(Method method, String fqnAnnotationName) { + return (String) getAnnotationValue(method, fqnAnnotationName, "value"); + } + + /** + * Checks if the method has been annotated with the given annotation (FQN class name) and if present, then returns + * the value attribute. + * + * @param method the field + * @param key the annotation key + * @param fqnAnnotationName the FQN of the annotation + * @return null if not annotated, otherwise the value, an empty string means annotation but has no + * value + */ + public static Object getAnnotationValue(Method method, String fqnAnnotationName, String key) { + for (Annotation ann : method.getAnnotations()) { + if (ann.annotationType().getName().equals(fqnAnnotationName)) { + try { + Method m = ann.getClass().getDeclaredMethod(key); + return m.invoke(ann); + } catch (Exception e) { + return null; + } + } + } + return null; + } + + /** + * Checks if the field has been annotated with the given annotation (FQN class name). + * + * @param field the field + * @param fqnAnnotationName the FQN of the annotation + * @return true if annotated or false if not + */ + public static boolean hasAnnotation(Field field, String fqnAnnotationName) { + for (Annotation ann : field.getAnnotations()) { + if (ann.annotationType().getName().equals(fqnAnnotationName)) { + return true; + } + } + return false; + } + + /** + * Checks if the field has been annotated with the given annotation (FQN class name) and if present, then returns + * the value attribute. + * + * @param field the field + * @param fqnAnnotationName the FQN of the annotation + * @return null if not annotated, otherwise the value, an empty string means annotation but has no + * value + */ + public static String getAnnotationValue(Field field, String fqnAnnotationName) { + return (String) getAnnotationValue(field, fqnAnnotationName, "value"); + } + + /** + * Checks if the field has been annotated with the given annotation (FQN class name) and if present, then returns + * the value attribute. + * + * @param field the field + * @param key the annotation key + * @param fqnAnnotationName the FQN of the annotation + * @return null if not annotated, otherwise the value, an empty string means annotation but has no + * value + */ + public static Object getAnnotationValue(Field field, String fqnAnnotationName, String key) { + for (Annotation ann : field.getAnnotations()) { + if (ann.annotationType().getName().equals(fqnAnnotationName)) { + try { + Method m = ann.getClass().getDeclaredMethod(key); + return m.invoke(ann); + } catch (Exception e) { + return null; + } + } + } + return null; + } + +} diff --git a/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java b/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java index 941188187bc..2afcdbd3f59 100644 --- a/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java +++ b/core/camel-util/src/main/java/org/apache/camel/util/ObjectHelper.java @@ -845,65 +845,53 @@ public final class ObjectHelper { /** * Returns a list of methods which are annotated with the given annotation * - * @param type the type to reflect on - * @param annotationType the annotation type - * @return a list of the methods found - */ + * @param type the type to reflect on + * @param annotationType the annotation type + * @return a list of the methods found + * @see AnnotationHelper + * @see AnnotationHelper + * @deprecated use AnnotationHelper + */ + @Deprecated(since = "4.13.0") public static List<Method> findMethodsWithAnnotation( Class<?> type, Class<? extends Annotation> annotationType) { - return findMethodsWithAnnotation(type, annotationType, false); + return AnnotationHelper.findMethodsWithAnnotation(type, annotationType); } /** * Returns a list of methods which are annotated with the given annotation * - * @param type the type to reflect on - * @param annotationType the annotation type - * @param checkMetaAnnotations check for meta annotations - * @return a list of the methods found - */ + * @param type the type to reflect on + * @param annotationType the annotation type + * @param checkMetaAnnotations check for meta annotations + * @return a list of the methods found + * @see AnnotationHelper + * @deprecated use AnnotationHelper + */ + @Deprecated(since = "4.13.0") public static List<Method> findMethodsWithAnnotation( Class<?> type, Class<? extends Annotation> annotationType, boolean checkMetaAnnotations) { - List<Method> answer = new ArrayList<>(); - do { - Method[] methods = type.getDeclaredMethods(); - for (Method method : methods) { - if (hasAnnotation(method, annotationType, checkMetaAnnotations)) { - answer.add(method); - } - } - type = type.getSuperclass(); - } while (type != null); - return answer; + return AnnotationHelper.findMethodsWithAnnotation(type, annotationType, checkMetaAnnotations); } /** * Checks if a Class or Method are annotated with the given annotation * - * @param elem the Class or Method to reflect on - * @param annotationType the annotation type - * @param checkMetaAnnotations check for meta annotations - * @return true if annotations is present - */ + * @param elem the Class or Method to reflect on + * @param annotationType the annotation type + * @param checkMetaAnnotations check for meta annotations + * @return true if annotations is present + * @see AnnotationHelper + * @deprecated use AnnotationHelper + */ + @Deprecated(since = "4.13.0") public static boolean hasAnnotation( AnnotatedElement elem, Class<? extends Annotation> annotationType, boolean checkMetaAnnotations) { - if (elem.isAnnotationPresent(annotationType)) { - return true; - } - if (checkMetaAnnotations) { - for (Annotation a : elem.getAnnotations()) { - for (Annotation meta : a.annotationType().getAnnotations()) { - if (meta.annotationType().getName().equals(annotationType.getName())) { - return true; - } - } - } - } - return false; + return AnnotationHelper.hasAnnotation(elem, annotationType, checkMetaAnnotations); } /** diff --git a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java b/core/camel-util/src/test/java/org/apache/camel/util/AnnotationHelperTest.java similarity index 50% copy from core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java copy to core/camel-util/src/test/java/org/apache/camel/util/AnnotationHelperTest.java index 54126091be9..305b1e61b45 100644 --- a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java +++ b/core/camel-util/src/test/java/org/apache/camel/util/AnnotationHelperTest.java @@ -16,15 +16,26 @@ */ package org.apache.camel.util; -public class MyPojo { +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; - private String name; +public class AnnotationHelperTest { - public String getName() { - return name; + @Test + public void testGetAnnotationByFQN() { + // no annotation + String value = AnnotationHelper.getAnnotationValue(AnnotationHelperTest.class, "org.junit.jupiter.api.DisplayName"); + Assertions.assertNull(value); + + // annotation with value + value = AnnotationHelper.getAnnotationValue(MyPojo.class, "org.junit.jupiter.api.DisplayName"); + Assertions.assertEquals("theNameHere", value); } - public void setName(String name) { - this.name = name; + @Test + public void testHasAnnotationByFQN() { + Assertions.assertFalse(AnnotationHelper.hasAnnotation(AnnotationHelperTest.class, "org.junit.jupiter.api.DisplayName")); + Assertions.assertTrue(AnnotationHelper.hasAnnotation(MyPojo.class, "org.junit.jupiter.api.DisplayName")); } + } diff --git a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java b/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java index 54126091be9..d05e1691068 100644 --- a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java +++ b/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java @@ -16,6 +16,9 @@ */ package org.apache.camel.util; +import org.junit.jupiter.api.DisplayName; + +@DisplayName("theNameHere") public class MyPojo { private String name; diff --git a/dsl/camel-kamelet-main/pom.xml b/dsl/camel-kamelet-main/pom.xml index ae78e954622..d6ae1783b78 100644 --- a/dsl/camel-kamelet-main/pom.xml +++ b/dsl/camel-kamelet-main/pom.xml @@ -161,22 +161,17 @@ <groupId>org.apache.camel</groupId> <artifactId>camel-tooling-maven</artifactId> </dependency> - <!-- optional spring annotation support --> + <!-- legacy Spring beans XML support --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-version}</version> - </dependency> - <!-- optional quarkus annotation support --> - <dependency> - <groupId>jakarta.enterprise</groupId> - <artifactId>jakarta.enterprise.cdi-api</artifactId> - <version>${jakarta-enterprise-cdi-api-version}</version> - </dependency> - <dependency> - <groupId>org.eclipse.microprofile.config</groupId> - <artifactId>microprofile-config-api</artifactId> - <version>${microprofile-config-version}</version> + <exclusions> + <exclusion> + <groupId>io.micrometer</groupId> + <artifactId>micrometer-observation</artifactId> + </exclusion> + </exclusions> </dependency> <!-- test --> diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java index daa31b4aee2..6ab6188461c 100644 --- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java +++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/BasePackageScanDownloadListener.java @@ -27,11 +27,6 @@ import java.util.function.Supplier; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.inject.Singleton; - -import javax.inject.Named; - import org.apache.camel.CamelConfiguration; import org.apache.camel.CamelContext; import org.apache.camel.CamelContextAware; @@ -40,14 +35,13 @@ import org.apache.camel.RuntimeCamelException; import org.apache.camel.spi.CamelBeanPostProcessor; import org.apache.camel.spi.PackageScanClassResolver; import org.apache.camel.spi.Registry; -import org.apache.camel.spi.annotations.Component; import org.apache.camel.support.PluginHelper; +import org.apache.camel.util.AnnotationHelper; import org.apache.camel.util.FileUtil; import org.apache.camel.util.IOHelper; import org.apache.camel.util.StringHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; public class BasePackageScanDownloadListener implements ArtifactDownloadListener, CamelContextAware { @@ -154,7 +148,9 @@ public class BasePackageScanDownloadListener implements ArtifactDownloadListener protected void basePackageScanQuarkus(String... basePackage) throws Exception { // we only want to scan via isolated classloader PackageScanClassResolver pscr = PluginHelper.getPackageScanClassResolver(camelContext); - Set<Class<?>> found = pscr.findAnnotated(Set.of(ApplicationScoped.class, Singleton.class), basePackage); + Set<Class<?>> found + = pscr.findByFilter(c -> AnnotationHelper.hasAnnotation(c, "jakarta.enterprise.context.ApplicationScoped") + || AnnotationHelper.hasAnnotation(c, "jakarta.inject.Singleton"), basePackage); for (Class<?> clazz : found) { // avoid duplicate if we scan other JARs that can same class from previous downloads String fqn = clazz.getName(); @@ -168,9 +164,9 @@ public class BasePackageScanDownloadListener implements ArtifactDownloadListener // @Named can dictate the name of the bean String name = null; - Named named = clazz.getAnnotation(Named.class); - if (named != null) { - name = named.value(); + var ann = AnnotationHelper.getAnnotationValue(clazz, "javax.inject.Named"); + if (ann != null) { + name = ann; } if (name == null || name.isBlank()) { name = clazz.getSimpleName(); @@ -186,7 +182,9 @@ public class BasePackageScanDownloadListener implements ArtifactDownloadListener protected void basePackageScanSpring(String... basePackage) throws Exception { // we only want to scan via isolated classloader PackageScanClassResolver pscr = PluginHelper.getPackageScanClassResolver(camelContext); - Set<Class<?>> found = pscr.findAnnotated(Set.of(Component.class, Service.class), basePackage); + Set<Class<?>> found + = pscr.findByFilter(c -> AnnotationHelper.hasAnnotation(c, "org.springframework.stereotype.Component") + || AnnotationHelper.hasAnnotation(c, "org.springframework.stereotype.Service"), basePackage); for (Class<?> clazz : found) { // avoid duplicate if we scan other JARs that can same class from previous downloads String fqn = clazz.getName(); @@ -199,13 +197,13 @@ public class BasePackageScanDownloadListener implements ArtifactDownloadListener LOG.debug("Discovered Spring @Component/@Service class: {}", clazz); String name = null; - var ann = clazz.getAnnotation(Component.class); + var ann = AnnotationHelper.getAnnotationValue(clazz, "org.springframework.stereotype.Component"); if (ann != null) { - name = ann.value(); + name = ann; } else { - var ann2 = clazz.getAnnotation(Service.class); + var ann2 = AnnotationHelper.getAnnotationValue(clazz, "org.springframework.stereotype.Service"); if (ann2 != null) { - name = ann2.value(); + name = ann2; } } if (name == null || name.isBlank()) { diff --git a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java index c18e1f9f25a..d246dbe8aca 100644 --- a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java +++ b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java @@ -22,12 +22,6 @@ import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; -import jakarta.enterprise.context.ApplicationScoped; -import jakarta.enterprise.inject.Produces; -import jakarta.inject.Inject; -import jakarta.inject.Named; -import jakarta.inject.Singleton; - import org.apache.camel.BindToRegistry; import org.apache.camel.CamelConfiguration; import org.apache.camel.CamelContext; @@ -46,16 +40,10 @@ import org.apache.camel.spi.ManagementStrategy; import org.apache.camel.spi.Registry; import org.apache.camel.spi.TypeConverterRegistry; import org.apache.camel.support.PluginHelper; +import org.apache.camel.util.AnnotationHelper; import org.apache.camel.util.ObjectHelper; import org.apache.camel.util.ReflectionHelper; import org.apache.camel.util.StringHelper; -import org.eclipse.microprofile.config.inject.ConfigProperty; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; -import org.springframework.stereotype.Service; /** * To enable camel/spring/quarkus based annotations for dependency injection when loading DSLs. @@ -205,13 +193,13 @@ public final class AnnotationDependencyInjection { return; } // @Component and @Service are the same - Component comp = clazz.getAnnotation(Component.class); - Service service = clazz.getAnnotation(Service.class); + String comp = AnnotationHelper.getAnnotationValue(clazz, "org.springframework.stereotype.Component"); + String service = AnnotationHelper.getAnnotationValue(clazz, "org.springframework.stereotype.Service"); if (comp != null || service != null) { - if (comp != null && ObjectHelper.isNotEmpty(comp.value())) { - name = comp.value(); - } else if (service != null && ObjectHelper.isNotEmpty(service.value())) { - name = service.value(); + if (ObjectHelper.isNotEmpty(comp)) { + name = comp; + } else if (ObjectHelper.isNotEmpty(service)) { + name = service; } if (name == null || name.isBlank()) { name = clazz.getSimpleName(); @@ -235,35 +223,38 @@ public final class AnnotationDependencyInjection { @Override public void onFieldInject(Field field, Object bean, String beanName) { - Autowired autowired = field.getAnnotation(Autowired.class); - if (autowired != null) { + boolean autowired = AnnotationHelper.hasAnnotation(field, "org.springframework.beans.factory.annotation.Autowired"); + if (autowired) { String name = null; - Qualifier qualifier = field.getAnnotation(Qualifier.class); - if (qualifier != null) { - name = qualifier.value(); + String named + = AnnotationHelper.getAnnotationValue(field, "org.springframework.beans.factory.annotation.Qualifier"); + if (ObjectHelper.isNotEmpty(named)) { + name = named; } try { ReflectionHelper.setField(field, bean, helper.getInjectionBeanValue(field.getType(), name)); } catch (NoSuchBeanException e) { - if (autowired.required()) { + Object required = AnnotationHelper.getAnnotationValue(field, + "org.springframework.beans.factory.annotation.Autowired", "required"); + if (Boolean.TRUE == required) { throw e; } // not required so ignore } } - Value value = field.getAnnotation(Value.class); + String value = AnnotationHelper.getAnnotationValue(field, "org.springframework.beans.factory.annotation.Value"); if (value != null) { ReflectionHelper.setField(field, bean, - helper.getInjectionPropertyValue(field.getType(), field.getGenericType(), value.value(), null, null)); + helper.getInjectionPropertyValue(field.getType(), field.getGenericType(), value, null, null)); } } @Override public void onMethodInject(Method method, Object bean, String beanName) { - Bean bi = method.getAnnotation(Bean.class); - if (bi != null) { + boolean bi = AnnotationHelper.hasAnnotation(method, "org.springframework.context.annotation.Bean"); + if (bi) { Object instance; if (lazyBean) { instance = (Supplier<Object>) () -> helper.getInjectionBeanMethodValue(context, method, bean, beanName, @@ -273,8 +264,14 @@ public final class AnnotationDependencyInjection { } if (instance != null) { String name = method.getName(); - if (bi.name().length > 0) { - name = bi.name()[0]; + String[] names = (String[]) AnnotationHelper.getAnnotationValue(method, + "org.springframework.context.annotation.Bean", "name"); + if (names == null) { + names = (String[]) AnnotationHelper.getAnnotationValue(method, + "org.springframework.context.annotation.Bean", "value"); + } + if (names != null && names.length > 0) { + name = names[0]; } bindBean(context, name, instance, method.getReturnType(), false); } @@ -291,12 +288,12 @@ public final class AnnotationDependencyInjection { return; } // @ApplicationScoped and @Singleton are considered the same - ApplicationScoped as = clazz.getAnnotation(ApplicationScoped.class); - Singleton ss = clazz.getAnnotation(Singleton.class); - if (as != null || ss != null) { - Named named = clazz.getAnnotation(Named.class); + boolean as = AnnotationHelper.hasAnnotation(clazz, "jakarta.enterprise.context.ApplicationScoped"); + boolean ss = AnnotationHelper.hasAnnotation(clazz, "jakarta.inject.Singleton"); + if (as || ss) { + String named = AnnotationHelper.getAnnotationValue(clazz, "jakarta.inject.Named"); if (named != null) { - name = named.value(); + name = named; } if (name == null || name.isBlank()) { name = clazz.getSimpleName(); @@ -320,35 +317,37 @@ public final class AnnotationDependencyInjection { @Override public void onFieldInject(Field field, Object bean, String beanName) { - Inject inject = field.getAnnotation(Inject.class); - if (inject != null) { + boolean inject = AnnotationHelper.hasAnnotation(field, "jakarta.inject.Inject"); + if (inject) { String name = null; - Named named = field.getAnnotation(Named.class); + String named = AnnotationHelper.getAnnotationValue(field, "jakarta.inject.Named"); if (named != null) { - name = named.value(); + name = named; } ReflectionHelper.setField(field, bean, helper.getInjectionBeanValue(field.getType(), name)); } - ConfigProperty cp = field.getAnnotation(ConfigProperty.class); - if (cp != null) { - String df = cp.defaultValue(); - if (ConfigProperty.UNCONFIGURED_VALUE.equals(df)) { + if (AnnotationHelper.hasAnnotation(field, "org.eclipse.microprofile.config.inject.ConfigProperty")) { + String name = (String) AnnotationHelper.getAnnotationValue(field, + "org.eclipse.microprofile.config.inject.ConfigProperty", "name"); + String df = (String) AnnotationHelper.getAnnotationValue(field, + "org.eclipse.microprofile.config.inject.ConfigProperty", "defaultValue"); + if ("org.eclipse.microprofile.config.configproperty.unconfigureddvalue".equals(df)) { df = null; } ReflectionHelper.setField(field, bean, - helper.getInjectionPropertyValue(field.getType(), field.getGenericType(), cp.name(), df, null)); + helper.getInjectionPropertyValue(field.getType(), field.getGenericType(), name, df, null)); } } @Override public void onMethodInject(Method method, Object bean, String beanName) { - Produces produces = method.getAnnotation(Produces.class); - Inject inject = method.getAnnotation(Inject.class); - Named bi = method.getAnnotation(Named.class); - if (produces != null || inject != null || bi != null) { - String an = produces != null ? "Produces" : "Inject"; + boolean produces = AnnotationHelper.hasAnnotation(method, "jakarta.enterprise.inject.Produces"); + boolean inject = AnnotationHelper.hasAnnotation(method, "jakarta.inject.Inject"); + boolean bi = AnnotationHelper.hasAnnotation(method, "jakarta.inject.Named"); + if (produces || inject || bi) { + String an = produces ? "Produces" : "Inject"; Object instance; if (lazyBean) { instance = (Supplier<Object>) () -> helper.getInjectionBeanMethodValue(context, method, bean, beanName, @@ -358,8 +357,9 @@ public final class AnnotationDependencyInjection { } if (instance != null) { String name = method.getName(); - if (bi != null && !bi.value().isBlank()) { - name = bi.value(); + String named = AnnotationHelper.getAnnotationValue(method, "jakarta.inject.Named"); + if (ObjectHelper.isNotEmpty(named)) { + name = named; } bindBean(context, name, instance, method.getReturnType(), false); } diff --git a/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/AnnotationDependencyInjectionTest.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/AnnotationDependencyInjectionTest.java new file mode 100644 index 00000000000..4a7a2dbf735 --- /dev/null +++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/AnnotationDependencyInjectionTest.java @@ -0,0 +1,55 @@ +/* + * 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.main; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.apache.camel.main.app.Bean1; +import org.apache.camel.main.app.MyNoValueSpringBean; +import org.apache.camel.main.app.MySpringBean; +import org.apache.camel.util.AnnotationHelper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class AnnotationDependencyInjectionTest { + + @Test + public void testSpringBean() throws Exception { + // no annotation + Object value = AnnotationHelper.getAnnotationValue(Bean1.class, "org.springframework.stereotype.Component"); + Assertions.assertNull(value); + + // annotation with no value + value = AnnotationHelper.getAnnotationValue(MyNoValueSpringBean.class, "org.springframework.stereotype.Component"); + Assertions.assertEquals("", value); + + // annotation with value + value = AnnotationHelper.getAnnotationValue(MySpringBean.class, "org.springframework.stereotype.Component"); + Assertions.assertEquals("theNameHere", value); + + Field f = MySpringBean.class.getDeclaredField("camelContext"); + value = AnnotationHelper.getAnnotationValue(f, "org.springframework.beans.factory.annotation.Autowired", "required"); + Assertions.assertEquals(Boolean.TRUE, value); + + Method m = MySpringBean.class.getDeclaredMethod("cheese"); + String[] names + = (String[]) AnnotationHelper.getAnnotationValue(m, "org.springframework.context.annotation.Bean", "value"); + Assertions.assertEquals("a1", names[0]); + Assertions.assertEquals("a2", names[1]); + } +} diff --git a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/MyNoValueSpringBean.java similarity index 79% copy from core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java copy to dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/MyNoValueSpringBean.java index 54126091be9..e56666ac346 100644 --- a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java +++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/MyNoValueSpringBean.java @@ -14,17 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.util; +package org.apache.camel.main.app; -public class MyPojo { +import org.springframework.stereotype.Component; - private String name; +@Component +public class MyNoValueSpringBean { - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } } diff --git a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/MySpringBean.java similarity index 64% copy from core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java copy to dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/MySpringBean.java index 54126091be9..74868c6e4a5 100644 --- a/core/camel-util/src/test/java/org/apache/camel/util/MyPojo.java +++ b/dsl/camel-kamelet-main/src/test/java/org/apache/camel/main/app/MySpringBean.java @@ -14,17 +14,22 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.camel.util; +package org.apache.camel.main.app; -public class MyPojo { +import org.apache.camel.CamelContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; - private String name; +@Component("theNameHere") +public class MySpringBean { - public String getName() { - return name; - } + @Autowired(required = true) + private CamelContext camelContext; - public void setName(String name) { - this.name = name; + @Bean({ "a1", "a2" }) + public String cheese() { + return "cheese"; } + }