16
16
17
17
package org .springframework .web .service .registry ;
18
18
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
-
26
19
import org .jspecify .annotations .Nullable ;
27
20
28
21
import org .springframework .beans .BeansException ;
45
38
import org .springframework .core .type .classreading .MetadataReader ;
46
39
import org .springframework .core .type .filter .AnnotationTypeFilter ;
47
40
import org .springframework .util .Assert ;
48
- import org .springframework .util .ClassUtils ;
49
41
import org .springframework .util .StringUtils ;
50
42
import org .springframework .web .service .annotation .HttpExchange ;
51
43
@@ -91,13 +83,13 @@ public abstract class AbstractHttpServiceRegistrar implements
91
83
92
84
private @ Nullable BeanFactory beanFactory ;
93
85
94
- private final Map < String , RegisteredGroup > groupMap = new LinkedHashMap <> ();
86
+ private final GroupsMetadata groupsMetadata = new GroupsMetadata ();
95
87
96
88
private @ Nullable ClassPathScanningCandidateComponentProvider scanner ;
97
89
98
90
99
91
/**
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
101
93
* remains {@link HttpServiceGroup.ClientType#UNSPECIFIED}.
102
94
* <p>By default, when this property is not set, then {@code REST_CLIENT}
103
95
* is used for any HTTP Service group whose client type remains unspecified.
@@ -141,7 +133,7 @@ public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefin
141
133
proxyRegistryBeanDef = new GenericBeanDefinition ();
142
134
proxyRegistryBeanDef .setBeanClass (HttpServiceProxyRegistryFactoryBean .class );
143
135
ConstructorArgumentValues args = proxyRegistryBeanDef .getConstructorArgumentValues ();
144
- args .addIndexedArgumentValue (0 , new LinkedHashMap < String , HttpServiceGroup > ());
136
+ args .addIndexedArgumentValue (0 , new GroupsMetadata ());
145
137
beanRegistry .registerBeanDefinition (proxyRegistryBeanName , proxyRegistryBeanDef );
146
138
}
147
139
else {
@@ -150,9 +142,10 @@ public final void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefin
150
142
151
143
mergeGroups (proxyRegistryBeanDef );
152
144
153
- this .groupMap . forEach (( groupName , group ) -> group .httpServiceTypeNames ().forEach (type -> {
145
+ this .groupsMetadata . forEachRegistration ( group -> group .httpServiceTypeNames ().forEach (type -> {
154
146
GenericBeanDefinition proxyBeanDef = new GenericBeanDefinition ();
155
147
proxyBeanDef .setBeanClassName (type );
148
+ String groupName = group .name ();
156
149
String beanName = (groupName + "#" + type );
157
150
proxyBeanDef .setInstanceSupplier (() -> getProxyInstance (proxyRegistryBeanName , groupName , type ));
158
151
if (!beanRegistry .containsBeanDefinition (beanName )) {
@@ -182,50 +175,23 @@ private ClassPathScanningCandidateComponentProvider getScanner() {
182
175
return this .scanner ;
183
176
}
184
177
185
- @ SuppressWarnings ("unchecked" )
186
178
private void mergeGroups (GenericBeanDefinition proxyRegistryBeanDef ) {
187
179
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 );
210
185
}
211
186
212
- private Object getProxyInstance (String registryBeanName , String groupName , String type ) {
187
+ private Object getProxyInstance (String registryBeanName , String groupName , String httpServiceType ) {
213
188
Assert .state (this .beanFactory != null , "BeanFactory has not been set" );
214
189
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 + "]" );
217
192
return proxy ;
218
193
}
219
194
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
-
229
195
230
196
/**
231
197
* Registry API to allow subclasses to register HTTP Services.
@@ -287,32 +253,23 @@ public GroupSpec forGroup(String name, HttpServiceGroup.ClientType clientType) {
287
253
return new DefaultGroupSpec (name , clientType );
288
254
}
289
255
256
+ /**
257
+ * Default implementation of {@link GroupSpec}.
258
+ */
290
259
private class DefaultGroupSpec implements GroupSpec {
291
260
292
- private final String groupName ;
293
-
294
- private final HttpServiceGroup .ClientType clientType ;
261
+ private final GroupsMetadata .Registration registration ;
295
262
296
263
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 );
311
266
}
312
267
313
268
@ Override
314
269
public GroupSpec register (Class <?>... serviceTypes ) {
315
- getOrCreateGroup ().addHttpServiceTypes (serviceTypes );
270
+ for (Class <?> serviceType : serviceTypes ) {
271
+ this .registration .httpServiceTypeNames ().add (serviceType .getName ());
272
+ }
316
273
return this ;
317
274
}
318
275
@@ -335,84 +292,10 @@ public GroupSpec detectInBasePackages(String... packageNames) {
335
292
private void detect (String packageName ) {
336
293
for (BeanDefinition definition : getScanner ().findCandidateComponents (packageName )) {
337
294
if (definition .getBeanClassName () != null ) {
338
- getOrCreateGroup ().addHttpServiceTypeName (definition .getBeanClassName ());
295
+ this . registration . httpServiceTypeNames ().add (definition .getBeanClassName ());
339
296
}
340
297
}
341
298
}
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 + "]" ;
416
299
}
417
300
}
418
301
0 commit comments