Skip to content

Commit

Permalink
Fix adding hints for EnvironmentRepositoryFactory classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
OlgaMaciaszek committed May 6, 2024
1 parent f70ecf6 commit 4bdb292
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,10 @@
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;

Expand All @@ -49,6 +47,7 @@
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;
Expand All @@ -70,8 +69,8 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL
"-env-repo-properties", EnvironmentRepositoryProperties.class);
Map<String, BeanDefinition> 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<String, BeanDefinition> getCompositeEnvironmentBeanDefinitions(
Expand Down Expand Up @@ -106,7 +105,7 @@ private static final class CompositeEnvironmentBeanFactoryInitializationAotContr

private final ConfigurableListableBeanFactory beanFactory;

private final Set<Class<? extends EnvironmentRepositoryProperties>> propertiesClasses = new HashSet<>();
private final Set<Class<?>> hintClasses = new HashSet<>();

private CompositeEnvironmentBeanFactoryInitializationAotContribution(
Map<String, BeanDefinition> propertyBeanDefinitions, Map<String, BeanDefinition> repoBeanDefinitions,
Expand All @@ -121,36 +120,23 @@ public void applyTo(GenerationContext generationContext,
BeanFactoryInitializationCode beanFactoryInitializationCode) {
GeneratedMethod environmentRepositoryPropertiesGeneratedMethod = beanFactoryInitializationCode.getMethods()
.add("registerCompositeEnvironmentRepositoryPropertiesBeanDefinitions",
this::generateRegisterPropertyBeanDefinitionsMethod);
this::generateRegisterBeanDefinitionsMethod);
beanFactoryInitializationCode
.addInitializer(environmentRepositoryPropertiesGeneratedMethod.toMethodReference());
generateRuntimeHints(generationContext.getRuntimeHints());
}

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<? extends EnvironmentRepositoryProperties> 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);
Expand All @@ -160,13 +146,16 @@ private void generateRegisterPropertyBeanDefinitionsMethod(MethodSpec.Builder me
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<? extends EnvironmentRepositoryProperties> propertiesClass = (Class<? extends EnvironmentRepositoryProperties>) propertyType;
propertiesClasses.add(propertiesClass);
if (matcher.find()) {
String repoBeanName = beanName.replace("repo-properties", "repo");
String factoryName = repoBeanDefinitions.get(repoBeanName).getFactoryBeanName();
Class<? extends EnvironmentRepositoryFactory<? extends EnvironmentRepository, ? extends EnvironmentRepositoryProperties>> factoryClass = (Class<? extends EnvironmentRepositoryFactory<? extends EnvironmentRepository, ? extends EnvironmentRepositoryProperties>>) CompositeUtils
.getFactoryClass(beanFactory, factoryName);
Type[] environmentRepositoryFactoryTypeParams = CompositeUtils
.getEnvironmentRepositoryFactoryTypeParams(factoryClass);
Class<? extends EnvironmentRepositoryProperties> repoClass = (Class<? extends EnvironmentRepositoryProperties>) environmentRepositoryFactoryTypeParams[0];
Class<? extends EnvironmentRepositoryProperties> propertiesClass = (Class<? extends EnvironmentRepositoryProperties>) environmentRepositoryFactoryTypeParams[1];
hintClasses.addAll(Set.of(repoClass, propertiesClass, factoryClass));
String indexString = matcher.group(3);
int index = Integer.parseInt(indexString);
String environmentConfigurationPropertyName = String
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -31,10 +31,12 @@
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 {

Expand Down Expand Up @@ -68,22 +70,25 @@ public static String getFactoryName(String type, ConfigurableListableBeanFactory
}

/**
* 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
* @return generic type params of the factory
*/
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<AnnotatedType> annotatedFactoryType = Arrays.stream(factoryClass.getAnnotatedInterfaces())
.filter(i -> {
ParameterizedType parameterizedType = (ParameterizedType) i.getType();
Expand All @@ -94,6 +99,25 @@ public static Type[] getEnvironmentRepositoryFactoryTypeParams(ConfigurableLista
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<Map<String, Object>> composite;
Expand Down

0 comments on commit 4bdb292

Please sign in to comment.