diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/aot/CompositeEnvironmentBeanFactoryInitializationAotProcessor.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/aot/CompositeEnvironmentBeanFactoryInitializationAotProcessor.java index ad3b4bd6..2d98cf99 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/aot/CompositeEnvironmentBeanFactoryInitializationAotProcessor.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/aot/CompositeEnvironmentBeanFactoryInitializationAotProcessor.java @@ -20,12 +20,10 @@ import java.lang.reflect.Type; import java.util.Arrays; import java.util.HashSet; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.lang.model.element.Modifier; @@ -49,6 +47,7 @@ import org.springframework.boot.context.properties.bind.Binder; import org.springframework.cloud.config.server.composite.CompositeEnvironmentBeanFactoryPostProcessor; import org.springframework.cloud.config.server.composite.CompositeUtils; import org.springframework.cloud.config.server.environment.EnvironmentRepository; +import org.springframework.cloud.config.server.environment.EnvironmentRepositoryFactory; import org.springframework.cloud.config.server.support.EnvironmentRepositoryProperties; import org.springframework.core.env.Environment; import org.springframework.javapoet.MethodSpec; @@ -70,8 +69,8 @@ public class CompositeEnvironmentBeanFactoryInitializationAotProcessor "-env-repo-properties", EnvironmentRepositoryProperties.class); Map repoBeanDefinitions = getCompositeEnvironmentBeanDefinitions(beanFactory, "-env-repo", EnvironmentRepository.class); - return new org.springframework.cloud.config.server.aot.CompositeEnvironmentBeanFactoryInitializationAotProcessor.CompositeEnvironmentBeanFactoryInitializationAotContribution( - propertyBeanDefinitions, repoBeanDefinitions, beanFactory); + return new CompositeEnvironmentBeanFactoryInitializationAotContribution(propertyBeanDefinitions, + repoBeanDefinitions, beanFactory); } private static Map getCompositeEnvironmentBeanDefinitions( @@ -106,7 +105,7 @@ public class CompositeEnvironmentBeanFactoryInitializationAotProcessor private final ConfigurableListableBeanFactory beanFactory; - private final Set> propertiesClasses = new HashSet<>(); + private final Set> hintClasses = new HashSet<>(); private CompositeEnvironmentBeanFactoryInitializationAotContribution( Map propertyBeanDefinitions, Map repoBeanDefinitions, @@ -121,7 +120,7 @@ public class CompositeEnvironmentBeanFactoryInitializationAotProcessor BeanFactoryInitializationCode beanFactoryInitializationCode) { GeneratedMethod environmentRepositoryPropertiesGeneratedMethod = beanFactoryInitializationCode.getMethods() .add("registerCompositeEnvironmentRepositoryPropertiesBeanDefinitions", - this::generateRegisterPropertyBeanDefinitionsMethod); + this::generateRegisterBeanDefinitionsMethod); beanFactoryInitializationCode .addInitializer(environmentRepositoryPropertiesGeneratedMethod.toMethodReference()); generateRuntimeHints(generationContext.getRuntimeHints()); @@ -129,28 +128,15 @@ public class CompositeEnvironmentBeanFactoryInitializationAotProcessor private void generateRuntimeHints(RuntimeHints runtimeHints) { ReflectionHints hints = runtimeHints.reflection(); - Stream.concat(propertyBeanDefinitions.values().stream(), repoBeanDefinitions.values().stream()) - .map(BeanDefinition::getBeanClassName).filter(Objects::nonNull).map(beanClassName -> { - try { - return Class.forName(beanClassName); - } - catch (ClassNotFoundException e) { - throw new RuntimeException("Class " + beanClassName + " could not be found", e); - } - }).forEach(beanClassName -> { - hints.registerType(TypeReference.of(beanClassName), MemberCategory.INTROSPECT_PUBLIC_METHODS, - MemberCategory.INTROSPECT_DECLARED_METHODS); - introspectPublicMethodsOnAllInterfaces(hints, beanClassName); - }); - for (Class propertiesClass : propertiesClasses) { - hints.registerType(TypeReference.of(propertiesClass), MemberCategory.INTROSPECT_PUBLIC_METHODS, + for (Class clazz : hintClasses) { + hints.registerType(TypeReference.of(clazz), MemberCategory.INVOKE_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_METHODS); - introspectPublicMethodsOnAllInterfaces(hints, propertiesClass); + introspectPublicMethodsOnAllInterfaces(hints, clazz); } } @SuppressWarnings("unchecked") - private void generateRegisterPropertyBeanDefinitionsMethod(MethodSpec.Builder method) { + private void generateRegisterBeanDefinitionsMethod(MethodSpec.Builder method) { method.addJavadoc( "Register the EnvironmentRepositoryProperties bean definitions for composite config data sources."); method.addModifiers(Modifier.PUBLIC); @@ -160,13 +146,16 @@ public class CompositeEnvironmentBeanFactoryInitializationAotProcessor Pattern findIndexPattern = Pattern.compile("(^.*)(-env-repo-properties)([0-9]+)$"); propertyBeanDefinitions.keySet().forEach(beanName -> { Matcher matcher = findIndexPattern.matcher(beanName); - String repoBeanName = beanName.replace("repo-properties", "repo"); - String factoryName = repoBeanDefinitions.get(repoBeanName).getFactoryBeanName(); - Type propertyType = CompositeUtils.getEnvironmentRepositoryFactoryTypeParams(beanFactory, - factoryName)[1]; - Class propertiesClass = (Class) propertyType; - propertiesClasses.add(propertiesClass); if (matcher.find()) { + String repoBeanName = beanName.replace("repo-properties", "repo"); + String factoryName = repoBeanDefinitions.get(repoBeanName).getFactoryBeanName(); + Class> factoryClass = (Class>) CompositeUtils + .getFactoryClass(beanFactory, factoryName); + Type[] environmentRepositoryFactoryTypeParams = CompositeUtils + .getEnvironmentRepositoryFactoryTypeParams(factoryClass); + Class repoClass = (Class) environmentRepositoryFactoryTypeParams[0]; + Class propertiesClass = (Class) environmentRepositoryFactoryTypeParams[1]; + hintClasses.addAll(Set.of(repoClass, propertiesClass, factoryClass)); String indexString = matcher.group(3); int index = Integer.parseInt(indexString); String environmentConfigurationPropertyName = String diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/composite/CompositeUtils.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/composite/CompositeUtils.java index 17db28af..c4721e9f 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/composite/CompositeUtils.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/composite/CompositeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,10 +31,12 @@ import org.springframework.boot.context.properties.bind.Binder; import org.springframework.cloud.config.server.environment.EnvironmentRepositoryFactory; import org.springframework.core.env.Environment; import org.springframework.core.type.MethodMetadata; +import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * @author Dylan Roberts + * @author Olga Maciaszek-Sharma */ public final class CompositeUtils { @@ -68,7 +70,7 @@ public final class CompositeUtils { } /** - * Given a Factory Name return the generic type parameters of the factory (The actual + * Given a Factory Name, return the generic type parameters of the factory (The actual * repository class, and its properties class). * @param beanFactory Spring Bean Factory * @param factoryName name of the factory @@ -76,14 +78,17 @@ public final class CompositeUtils { */ public static Type[] getEnvironmentRepositoryFactoryTypeParams(ConfigurableListableBeanFactory beanFactory, String factoryName) { - MethodMetadata methodMetadata = (MethodMetadata) beanFactory.getBeanDefinition(factoryName).getSource(); - Class factoryClass = null; - try { - factoryClass = Class.forName(methodMetadata.getReturnTypeName()); - } - catch (ClassNotFoundException e) { - throw new IllegalStateException(e); - } + Class factoryClass = getFactoryClass(beanFactory, factoryName); + return getEnvironmentRepositoryFactoryTypeParams(factoryClass); + } + + /** + * Given a Factory {@link Class}, return the generic type parameters of the factory + * (The actual repository class, and its properties class). + * @param factoryClass Factory {@link Class} + * @return generic type params of the factory + */ + public static Type[] getEnvironmentRepositoryFactoryTypeParams(Class factoryClass) { Optional annotatedFactoryType = Arrays.stream(factoryClass.getAnnotatedInterfaces()) .filter(i -> { ParameterizedType parameterizedType = (ParameterizedType) i.getType(); @@ -94,6 +99,25 @@ public final class CompositeUtils { return factoryParameterizedType.getActualTypeArguments(); } + /** + * Given a Factory Name, return the Factory {@link Class}. + * @param beanFactory Spring Bean Factory + * @param factoryName name of the factory + * @return factory {@link Class} + */ + public static Class getFactoryClass(ConfigurableListableBeanFactory beanFactory, String factoryName) { + MethodMetadata methodMetadata = (MethodMetadata) beanFactory.getBeanDefinition(factoryName).getSource(); + Assert.notNull(methodMetadata, "Factory MethodMetadata cannot be null."); + Class factoryClass; + try { + factoryClass = Class.forName(methodMetadata.getReturnTypeName()); + } + catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } + return factoryClass; + } + static class CompositeConfig { List> composite;