Skip to content

Commit 0608d8e

Browse files
committed
Fix client bean naming.
1 parent 12f6b9f commit 0608d8e

File tree

3 files changed

+36
-16
lines changed

3 files changed

+36
-16
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/interfaceclients/AbstractInterfaceClientsImportRegistrar.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,20 @@
1818

1919
import java.lang.annotation.Annotation;
2020
import java.util.HashSet;
21+
import java.util.List;
2122
import java.util.Set;
2223

24+
import org.springframework.beans.factory.ListableBeanFactory;
2325
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
2426
import org.springframework.beans.factory.config.BeanDefinition;
27+
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
2528
import org.springframework.context.EnvironmentAware;
2629
import org.springframework.context.ResourceLoaderAware;
2730
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
2831
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
2932
import org.springframework.core.env.Environment;
3033
import org.springframework.core.io.ResourceLoader;
31-
import org.springframework.core.type.AnnotationMetadata;
3234
import org.springframework.core.type.filter.AnnotationTypeFilter;
33-
import org.springframework.util.ClassUtils;
3435

3536
/**
3637
* @author Olga Maciaszek-Sharma
@@ -43,12 +44,12 @@ public abstract class AbstractInterfaceClientsImportRegistrar
4344

4445
private ResourceLoader resourceLoader;
4546

46-
protected Set<BeanDefinition> discoverCandidateComponents(AnnotationMetadata metadata) {
47+
protected Set<BeanDefinition> discoverCandidateComponents(ListableBeanFactory beanFactory) {
4748
Set<BeanDefinition> candidateComponents = new HashSet<>();
4849
ClassPathScanningCandidateComponentProvider scanner = getScanner();
4950
scanner.setResourceLoader(this.resourceLoader);
5051
scanner.addIncludeFilter(new AnnotationTypeFilter(getAnnotation()));
51-
Set<String> basePackages = Set.of(ClassUtils.getPackageName(metadata.getClassName()));
52+
List<String> basePackages = AutoConfigurationPackages.get(beanFactory);
5253
for (String basePackage : basePackages) {
5354
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
5455
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/interfaceclients/http/HttpClient.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
@Documented
3131
public @interface HttpClient {
3232

33-
String value() default "";
33+
String value();
34+
35+
String beanName() default "";
3436

3537
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/interfaceclients/http/HttpInterfaceClientsImportRegistrar.java

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
package org.springframework.boot.autoconfigure.interfaceclients.http;
1818

1919
import java.lang.annotation.Annotation;
20+
import java.text.Normalizer;
2021
import java.util.Set;
2122

2223
import org.apache.commons.logging.Log;
2324
import org.apache.commons.logging.LogFactory;
25+
import org.apache.commons.text.CaseUtils;
2426

2527
import org.springframework.beans.factory.ListableBeanFactory;
2628
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
@@ -33,7 +35,6 @@
3335
import org.springframework.core.type.AnnotationMetadata;
3436
import org.springframework.util.Assert;
3537
import org.springframework.util.ObjectUtils;
36-
import org.springframework.util.StringUtils;
3738

3839
/**
3940
* @author Olga Maciaszek-Sharma
@@ -43,19 +44,24 @@ public class HttpInterfaceClientsImportRegistrar extends AbstractInterfaceClient
4344

4445
private static final Log logger = LogFactory.getLog(HttpInterfaceClientsImportRegistrar.class);
4546

47+
private static final String INTERFACE_CLIENT_SUFFIX = "InterfaceClient";
48+
49+
private static final String BEAN_NAME_ATTRIBUTE_NAME = "beanName";
50+
4651
@Override
4752
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
4853
Assert.isInstanceOf(ListableBeanFactory.class, registry,
4954
"Registry must be an instance of " + ListableBeanFactory.class.getSimpleName());
50-
Set<BeanDefinition> candidateComponents = discoverCandidateComponents(metadata);
55+
ListableBeanFactory beanFactory = (ListableBeanFactory) registry;
56+
Set<BeanDefinition> candidateComponents = discoverCandidateComponents(beanFactory);
5157
for (BeanDefinition candidateComponent : candidateComponents) {
5258
if (candidateComponent instanceof AnnotatedBeanDefinition beanDefinition) {
53-
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
54-
Assert.isTrue(annotationMetadata.isInterface(),
59+
AnnotationMetadata annotatedBeanMetadata = beanDefinition.getMetadata();
60+
Assert.isTrue(annotatedBeanMetadata.isInterface(),
5561
getAnnotation().getSimpleName() + "can only be placed on an interface.");
56-
MergedAnnotation<? extends Annotation> annotation = annotationMetadata.getAnnotations()
62+
MergedAnnotation<? extends Annotation> annotation = annotatedBeanMetadata.getAnnotations()
5763
.get(getAnnotation());
58-
String beanClassName = annotationMetadata.getClassName();
64+
String beanClassName = annotatedBeanMetadata.getClassName();
5965
Class<?> beanClass;
6066
try {
6167
beanClass = Class.forName(beanClassName);
@@ -66,20 +72,31 @@ public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionR
6672
}
6773
throw new RuntimeException(e);
6874
}
69-
String clientName = !ObjectUtils.isEmpty(annotation.getString(MergedAnnotation.VALUE))
70-
? annotation.getString(MergedAnnotation.VALUE) : StringUtils.uncapitalize(beanClassName);
71-
ListableBeanFactory beanFactory = (ListableBeanFactory) registry;
75+
// TODO: consider naming conventions: value of the annotation is the
76+
// qualifier to look for related beans
77+
// TODO: while the actual beanName corresponds to the simple class name
78+
// suffixed with InterfaceClient
79+
String clientQualifier = annotation.getString(MergedAnnotation.VALUE);
80+
String beanName = !ObjectUtils.isEmpty(annotation.getString(BEAN_NAME_ATTRIBUTE_NAME))
81+
? annotation.getString(BEAN_NAME_ATTRIBUTE_NAME) : buildBeanName(clientQualifier);
7282
HttpInterfaceClientAdapter adapter = beanFactory.getBean(HttpInterfaceClientAdapter.class);
7383
BeanDefinition definition = BeanDefinitionBuilder
7484
.rootBeanDefinition(ResolvableType.forClass(beanClass),
75-
() -> adapter.createClient(beanFactory, clientName, beanClass))
85+
() -> adapter.createClient(beanFactory, clientQualifier, beanClass))
7686
.getBeanDefinition();
77-
registry.registerBeanDefinition(clientName, definition);
87+
registry.registerBeanDefinition(beanName, definition);
7888

7989
}
8090
}
8191
}
8292

93+
private String buildBeanName(String clientQualifier) {
94+
// TODO: research Normalizer form types
95+
String normalised = Normalizer.normalize(clientQualifier, Normalizer.Form.NFD);
96+
String camelCased = CaseUtils.toCamelCase(normalised, false, '-', '_');
97+
return camelCased + INTERFACE_CLIENT_SUFFIX;
98+
}
99+
83100
@Override
84101
protected Class<? extends Annotation> getAnnotation() {
85102
return HttpClient.class;

0 commit comments

Comments
 (0)