Skip to content

Commit 302f04e

Browse files
committed
Replace Map argument with GroupsMetadata
In preparation for HTTP Service registry AOT support. See gh-33992
1 parent 1c0bcba commit 302f04e

File tree

5 files changed

+211
-147
lines changed

5 files changed

+211
-147
lines changed

Diff for: spring-web/src/main/java/org/springframework/web/service/registry/AbstractHttpServiceRegistrar.java

+23-140
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@
1616

1717
package org.springframework.web.service.registry;
1818

19-
import java.util.Collection;
20-
import java.util.LinkedHashMap;
21-
import java.util.LinkedHashSet;
22-
import java.util.Map;
23-
import java.util.Set;
24-
import java.util.stream.Collectors;
25-
2619
import org.jspecify.annotations.Nullable;
2720

2821
import org.springframework.beans.BeansException;
@@ -45,7 +38,6 @@
4538
import org.springframework.core.type.classreading.MetadataReader;
4639
import org.springframework.core.type.filter.AnnotationTypeFilter;
4740
import org.springframework.util.Assert;
48-
import org.springframework.util.ClassUtils;
4941
import org.springframework.util.StringUtils;
5042
import org.springframework.web.service.annotation.HttpExchange;
5143

@@ -91,13 +83,13 @@ public abstract class AbstractHttpServiceRegistrar implements
9183

9284
private @Nullable BeanFactory beanFactory;
9385

94-
private final Map<String, RegisteredGroup> groupMap = new LinkedHashMap<>();
86+
private final GroupsMetadata groupsMetadata = new GroupsMetadata();
9587

9688
private @Nullable ClassPathScanningCandidateComponentProvider scanner;
9789

9890

9991
/**
100-
* Set the client type to use when the client type for an HTTP Service group
92+
* Set the client type to use when an HTTP Service group's client type
10193
* remains {@link HttpServiceGroup.ClientType#UNSPECIFIED}.
10294
* <p>By default, when this property is not set, then {@code REST_CLIENT}
10395
* is used for any HTTP Service group whose client type remains unspecified.
@@ -141,7 +133,7 @@ public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefin
141133
proxyRegistryBeanDef = new GenericBeanDefinition();
142134
proxyRegistryBeanDef.setBeanClass(HttpServiceProxyRegistryFactoryBean.class);
143135
ConstructorArgumentValues args = proxyRegistryBeanDef.getConstructorArgumentValues();
144-
args.addIndexedArgumentValue(0, new LinkedHashMap<String, HttpServiceGroup>());
136+
args.addIndexedArgumentValue(0, new GroupsMetadata());
145137
beanRegistry.registerBeanDefinition(proxyRegistryBeanName, proxyRegistryBeanDef);
146138
}
147139
else {
@@ -150,9 +142,10 @@ public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefin
150142

151143
mergeGroups(proxyRegistryBeanDef);
152144

153-
this.groupMap.forEach((groupName, group) -> group.httpServiceTypeNames().forEach(type -> {
145+
this.groupsMetadata.forEachRegistration(group -> group.httpServiceTypeNames().forEach(type -> {
154146
GenericBeanDefinition proxyBeanDef = new GenericBeanDefinition();
155147
proxyBeanDef.setBeanClassName(type);
148+
String groupName = group.name();
156149
String beanName = (groupName + "#" + type);
157150
proxyBeanDef.setInstanceSupplier(() -> getProxyInstance(proxyRegistryBeanName, groupName, type));
158151
if (!beanRegistry.containsBeanDefinition(beanName)) {
@@ -182,50 +175,23 @@ private ClassPathScanningCandidateComponentProvider getScanner() {
182175
return this.scanner;
183176
}
184177

185-
@SuppressWarnings("unchecked")
186178
private void mergeGroups(GenericBeanDefinition proxyRegistryBeanDef) {
187179
ConstructorArgumentValues args = proxyRegistryBeanDef.getConstructorArgumentValues();
188-
ConstructorArgumentValues.ValueHolder valueHolder = args.getArgumentValue(0, Map.class);
189-
Assert.state(valueHolder != null, "Expected Map constructor argument at index 0");
190-
Map<String, RegisteredGroup> targetMap = (Map<String, RegisteredGroup>) valueHolder.getValue();
191-
Assert.state(targetMap != null, "No constructor argument value");
192-
193-
this.groupMap.forEach((name, group) -> {
194-
RegisteredGroup previousGroup = targetMap.putIfAbsent(name, group);
195-
if (previousGroup != null) {
196-
if (!compatibleClientTypes(group.clientType(), previousGroup.clientType())) {
197-
throw new IllegalArgumentException("ClientType conflict for group '" + name + "'");
198-
}
199-
previousGroup.addHttpServiceTypeNames(group.httpServiceTypeNames());
200-
}
201-
});
202-
}
203-
204-
private static boolean compatibleClientTypes(
205-
HttpServiceGroup.ClientType clientTypeA, HttpServiceGroup.ClientType clientTypeB) {
206-
207-
return (clientTypeA == clientTypeB ||
208-
clientTypeA == HttpServiceGroup.ClientType.UNSPECIFIED ||
209-
clientTypeB == HttpServiceGroup.ClientType.UNSPECIFIED);
180+
ConstructorArgumentValues.ValueHolder valueHolder = args.getArgumentValue(0, GroupsMetadata.class);
181+
Assert.state(valueHolder != null, "Expected GroupsMetadata constructor argument at index 0");
182+
GroupsMetadata target = (GroupsMetadata) valueHolder.getValue();
183+
Assert.state(target != null, "No constructor argument value");
184+
target.mergeWith(this.groupsMetadata);
210185
}
211186

212-
private Object getProxyInstance(String registryBeanName, String groupName, String type) {
187+
private Object getProxyInstance(String registryBeanName, String groupName, String httpServiceType) {
213188
Assert.state(this.beanFactory != null, "BeanFactory has not been set");
214189
HttpServiceProxyRegistry registry = this.beanFactory.getBean(registryBeanName, HttpServiceProxyRegistry.class);
215-
Object proxy = registry.getClient(groupName, loadClass(type));
216-
Assert.notNull(proxy, "No proxy for HTTP Service [" + type + "]");
190+
Object proxy = registry.getClient(groupName, GroupsMetadata.loadClass(httpServiceType));
191+
Assert.notNull(proxy, "No proxy for HTTP Service [" + httpServiceType + "]");
217192
return proxy;
218193
}
219194

220-
private static Class<?> loadClass(String type) {
221-
try {
222-
return ClassUtils.forName(type, AbstractHttpServiceRegistrar.class.getClassLoader());
223-
}
224-
catch (ClassNotFoundException ex) {
225-
throw new IllegalStateException("Failed to load '" + type + "'", ex);
226-
}
227-
}
228-
229195

230196
/**
231197
* Registry API to allow subclasses to register HTTP Services.
@@ -287,32 +253,23 @@ public GroupSpec forGroup(String name, HttpServiceGroup.ClientType clientType) {
287253
return new DefaultGroupSpec(name, clientType);
288254
}
289255

256+
/**
257+
* Default implementation of {@link GroupSpec}.
258+
*/
290259
private class DefaultGroupSpec implements GroupSpec {
291260

292-
private final String groupName;
293-
294-
private final HttpServiceGroup.ClientType clientType;
261+
private final GroupsMetadata.Registration registration;
295262

296263
public DefaultGroupSpec(String groupName, HttpServiceGroup.ClientType clientType) {
297-
this.groupName = groupName;
298-
this.clientType = initClientType(clientType);
299-
}
300-
301-
private HttpServiceGroup.ClientType initClientType(HttpServiceGroup.ClientType clientType) {
302-
if (clientType != HttpServiceGroup.ClientType.UNSPECIFIED) {
303-
return clientType;
304-
}
305-
else if (defaultClientType != HttpServiceGroup.ClientType.UNSPECIFIED) {
306-
return defaultClientType;
307-
}
308-
else {
309-
return HttpServiceGroup.ClientType.REST_CLIENT;
310-
}
264+
clientType = (clientType != HttpServiceGroup.ClientType.UNSPECIFIED ? clientType : defaultClientType);
265+
this.registration = groupsMetadata.getOrCreateGroup(groupName, clientType);
311266
}
312267

313268
@Override
314269
public GroupSpec register(Class<?>... serviceTypes) {
315-
getOrCreateGroup().addHttpServiceTypes(serviceTypes);
270+
for (Class<?> serviceType : serviceTypes) {
271+
this.registration.httpServiceTypeNames().add(serviceType.getName());
272+
}
316273
return this;
317274
}
318275

@@ -335,84 +292,10 @@ public GroupSpec detectInBasePackages(String... packageNames) {
335292
private void detect(String packageName) {
336293
for (BeanDefinition definition : getScanner().findCandidateComponents(packageName)) {
337294
if (definition.getBeanClassName() != null) {
338-
getOrCreateGroup().addHttpServiceTypeName(definition.getBeanClassName());
295+
this.registration.httpServiceTypeNames().add(definition.getBeanClassName());
339296
}
340297
}
341298
}
342-
343-
private RegisteredGroup getOrCreateGroup() {
344-
return groupMap.computeIfAbsent(this.groupName, name -> new RegisteredGroup(name, this.clientType));
345-
}
346-
}
347-
}
348-
349-
350-
/**
351-
* A simple holder of registered HTTP Service type names, deferring the
352-
* loading of classes until {@link #httpServiceTypes()} is called.
353-
*/
354-
private static class RegisteredGroup implements HttpServiceGroup {
355-
356-
private final String name;
357-
358-
private final Set<String> httpServiceTypeNames = new LinkedHashSet<>();
359-
360-
private final ClientType clientType;
361-
362-
public RegisteredGroup(String name, ClientType clientType) {
363-
this.name = name;
364-
this.clientType = clientType;
365-
}
366-
367-
@Override
368-
public String name() {
369-
return this.name;
370-
}
371-
372-
public Set<String> httpServiceTypeNames() {
373-
return this.httpServiceTypeNames;
374-
}
375-
376-
@Override
377-
public Set<Class<?>> httpServiceTypes() {
378-
return this.httpServiceTypeNames.stream()
379-
.map(AbstractHttpServiceRegistrar::loadClass)
380-
.collect(Collectors.toSet());
381-
}
382-
383-
@Override
384-
public ClientType clientType() {
385-
return this.clientType;
386-
}
387-
388-
public void addHttpServiceTypes(Class<?>... httpServiceTypes) {
389-
for (Class<?> type : httpServiceTypes) {
390-
this.httpServiceTypeNames.add(type.getName());
391-
}
392-
}
393-
394-
public void addHttpServiceTypeNames(Collection<String> httpServiceTypeNames) {
395-
this.httpServiceTypeNames.addAll(httpServiceTypeNames);
396-
}
397-
398-
public void addHttpServiceTypeName(String httpServiceTypeName) {
399-
this.httpServiceTypeNames.add(httpServiceTypeName);
400-
}
401-
402-
@Override
403-
public final boolean equals(Object other) {
404-
return (other instanceof RegisteredGroup otherGroup && this.name.equals(otherGroup.name));
405-
}
406-
407-
@Override
408-
public int hashCode() {
409-
return this.name.hashCode();
410-
}
411-
412-
@Override
413-
public String toString() {
414-
return "RegisteredGroup[name='" + this.name + "', httpServiceTypes=" +
415-
this.httpServiceTypeNames + ", clientType=" + this.clientType + "]";
416299
}
417300
}
418301

0 commit comments

Comments
 (0)