Add HTTP Service registrar tests

Closes gh-33992
This commit is contained in:
rstoyanchev
2025-03-31 08:48:11 +00:00
parent 42409e21fa
commit 1c0bcba587
10 changed files with 435 additions and 51 deletions

View File

@@ -46,6 +46,7 @@ import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.service.annotation.HttpExchange;
/**
@@ -123,12 +124,17 @@ public abstract class AbstractHttpServiceRegistrar implements
@Override
public final void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry beanRegistry,
BeanNameGenerator beanNameGenerator) {
AnnotationMetadata metadata, BeanDefinitionRegistry registry, BeanNameGenerator generator) {
registerHttpServices(new DefaultGroupRegistry(), importingClassMetadata);
registerBeanDefinitions(metadata, registry);
}
String proxyRegistryBeanName = HttpServiceProxyRegistry.class.getName();
@Override
public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry beanRegistry) {
registerHttpServices(new DefaultGroupRegistry(), metadata);
String proxyRegistryBeanName = StringUtils.uncapitalize(HttpServiceProxyRegistry.class.getSimpleName());
GenericBeanDefinition proxyRegistryBeanDef;
if (!beanRegistry.containsBeanDefinition(proxyRegistryBeanName)) {
@@ -142,12 +148,12 @@ public abstract class AbstractHttpServiceRegistrar implements
proxyRegistryBeanDef = (GenericBeanDefinition) beanRegistry.getBeanDefinition(proxyRegistryBeanName);
}
mergeHttpServices(proxyRegistryBeanDef);
mergeGroups(proxyRegistryBeanDef);
this.groupMap.forEach((groupName, group) -> group.httpServiceTypeNames().forEach(type -> {
GenericBeanDefinition proxyBeanDef = new GenericBeanDefinition();
proxyBeanDef.setBeanClassName(type);
String beanName = (groupName + "." + beanNameGenerator.generateBeanName(proxyBeanDef, beanRegistry));
String beanName = (groupName + "#" + type);
proxyBeanDef.setInstanceSupplier(() -> getProxyInstance(proxyRegistryBeanName, groupName, type));
if (!beanRegistry.containsBeanDefinition(beanName)) {
beanRegistry.registerBeanDefinition(beanName, proxyBeanDef);
@@ -155,10 +161,6 @@ public abstract class AbstractHttpServiceRegistrar implements
}));
}
@Override
public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
}
/**
* This method is called before any bean definition registrations are made.
* Subclasses must implement it to register the HTTP Services for which bean
@@ -181,7 +183,7 @@ public abstract class AbstractHttpServiceRegistrar implements
}
@SuppressWarnings("unchecked")
private void mergeHttpServices(GenericBeanDefinition proxyRegistryBeanDef) {
private void mergeGroups(GenericBeanDefinition proxyRegistryBeanDef) {
ConstructorArgumentValues args = proxyRegistryBeanDef.getConstructorArgumentValues();
ConstructorArgumentValues.ValueHolder valueHolder = args.getArgumentValue(0, Map.class);
Assert.state(valueHolder != null, "Expected Map constructor argument at index 0");
@@ -233,7 +235,9 @@ public abstract class AbstractHttpServiceRegistrar implements
/**
* Perform HTTP Service registrations for the given group.
*/
GroupSpec forGroup(String name);
default GroupSpec forGroup(String name) {
return forGroup(name, HttpServiceGroup.ClientType.UNSPECIFIED);
}
/**
* Variant of {@link #forGroup(String)} with a client type.
@@ -278,11 +282,6 @@ public abstract class AbstractHttpServiceRegistrar implements
*/
private class DefaultGroupRegistry implements GroupRegistry {
@Override
public GroupSpec forGroup(String name) {
return forGroup(name, HttpServiceGroup.ClientType.UNSPECIFIED);
}
@Override
public GroupSpec forGroup(String name, HttpServiceGroup.ClientType clientType) {
return new DefaultGroupSpec(name, clientType);
@@ -313,14 +312,14 @@ public abstract class AbstractHttpServiceRegistrar implements
@Override
public GroupSpec register(Class<?>... serviceTypes) {
getOrCreateGroup(groupName, clientType).addHttpServiceTypes(serviceTypes);
getOrCreateGroup().addHttpServiceTypes(serviceTypes);
return this;
}
@Override
public GroupSpec detectInBasePackages(Class<?>... packageClasses) {
for (Class<?> packageClass : packageClasses) {
detect(this.groupName, this.clientType, packageClass.getPackageName());
detect(packageClass.getPackageName());
}
return this;
}
@@ -328,21 +327,21 @@ public abstract class AbstractHttpServiceRegistrar implements
@Override
public GroupSpec detectInBasePackages(String... packageNames) {
for (String packageName : packageNames) {
detect(this.groupName, this.clientType, packageName);
detect(packageName);
}
return this;
}
private void detect(String groupName, HttpServiceGroup.ClientType clientType, String packageName) {
private void detect(String packageName) {
for (BeanDefinition definition : getScanner().findCandidateComponents(packageName)) {
if (definition.getBeanClassName() != null) {
getOrCreateGroup(groupName, clientType).addHttpServiceTypeName(definition.getBeanClassName());
getOrCreateGroup().addHttpServiceTypeName(definition.getBeanClassName());
}
}
}
private RegisteredGroup getOrCreateGroup(String groupName, HttpServiceGroup.ClientType clientType) {
return groupMap.computeIfAbsent(groupName, name -> new RegisteredGroup(name, clientType));
private RegisteredGroup getOrCreateGroup() {
return groupMap.computeIfAbsent(this.groupName, name -> new RegisteredGroup(name, this.clientType));
}
}
}
@@ -376,7 +375,7 @@ public abstract class AbstractHttpServiceRegistrar implements
@Override
public Set<Class<?>> httpServiceTypes() {
return httpServiceTypeNames.stream()
return this.httpServiceTypeNames.stream()
.map(AbstractHttpServiceRegistrar::loadClass)
.collect(Collectors.toSet());
}

View File

@@ -27,7 +27,7 @@ import org.springframework.core.type.AnnotationMetadata;
* @author Rossen Stoyanchev
* @since 7.0
*/
final class AnnotationHttpServiceRegistrar extends AbstractHttpServiceRegistrar {
class AnnotationHttpServiceRegistrar extends AbstractHttpServiceRegistrar {
@Override
protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata importMetadata) {

View File

@@ -96,10 +96,10 @@ public final class HttpServiceProxyRegistryFactoryBean
Assert.notNull(this.applicationContext, "ApplicationContext not initialized");
// Apply group configurers
this.groupSet.forEach(group ->
this.applicationContext.getBeanProvider(group.getConfigurerType())
.orderedStream()
.forEach(configurer -> configurer.configureGroups(new DefaultGroups<>(group.clientType()))));
groupAdapters.forEach((clientType, groupAdapter) ->
this.applicationContext.getBeanProvider(groupAdapter.getConfigurerType())
.orderedStream()
.forEach(configurer -> configurer.configureGroups(new DefaultGroups<>(clientType))));
// Create proxies
Map<String, Map<Class<?>, Object>> groupProxyMap = this.groupSet.stream()
@@ -193,13 +193,13 @@ public final class HttpServiceProxyRegistryFactoryBean
}
public Map<Class<?>, Object> createProxies() {
Map<Class<?>, Object> proxyMap = new LinkedHashMap<>(httpServiceTypes().size());
Map<Class<?>, Object> map = new LinkedHashMap<>(httpServiceTypes().size());
HttpExchangeAdapter exchangeAdapter = initExchangeAdapter();
HttpServiceProxyFactory.Builder proxyFactoryBuilder = HttpServiceProxyFactory.builderFor(exchangeAdapter);
this.proxyFactoryConfigurer.accept(this, proxyFactoryBuilder);
HttpServiceProxyFactory proxyFactory = proxyFactoryBuilder.build();
httpServiceTypes().forEach(type -> proxyMap.put(type, proxyFactory.createClient(type)));
return proxyMap;
HttpServiceProxyFactory factory = proxyFactoryBuilder.build();
httpServiceTypes().forEach(type -> map.put(type, factory.createClient(type)));
return map;
}
@SuppressWarnings("unchecked")
@@ -219,12 +219,10 @@ public final class HttpServiceProxyRegistryFactoryBean
*/
private final class DefaultGroups<CB> implements HttpServiceGroupConfigurer.Groups<CB> {
private final HttpServiceGroup.ClientType clientType;
private @Nullable Predicate<HttpServiceGroup> filter;
private Predicate<HttpServiceGroup> filter;
DefaultGroups(HttpServiceGroup.ClientType clientType) {
this.clientType = clientType;
this.filter = group -> group.clientType().equals(clientType);
}
@Override
@@ -234,7 +232,7 @@ public final class HttpServiceProxyRegistryFactoryBean
@Override
public HttpServiceGroupConfigurer.Groups<CB> filter(Predicate<HttpServiceGroup> predicate) {
this.filter = (this.filter != null ? this.filter.or(predicate) : predicate);
this.filter = this.filter.or(predicate);
return this;
}
@@ -260,10 +258,8 @@ public final class HttpServiceProxyRegistryFactoryBean
BiConsumer<HttpServiceGroup, CB> clientConfigurer,
BiConsumer<HttpServiceGroup, HttpServiceProxyFactory.Builder> proxyFactoryConfigurer) {
groupSet.stream()
.filter(group -> group.clientType().equals(this.clientType))
.filter(groups -> this.filter == null || this.filter.test(groups))
.forEach(group -> group.apply(clientConfigurer, proxyFactoryConfigurer));
groupSet.stream().filter(this.filter).forEach(group ->
group.apply(clientConfigurer, proxyFactoryConfigurer));
}
}