16
16
17
17
package org .springframework .web .service .registry ;
18
18
19
- import java .util .Arrays ;
19
+ import java .util .Collection ;
20
20
import java .util .LinkedHashMap ;
21
21
import java .util .LinkedHashSet ;
22
22
import java .util .Map ;
23
23
import java .util .Set ;
24
+ import java .util .stream .Collectors ;
24
25
25
26
import org .jspecify .annotations .Nullable ;
26
27
@@ -89,7 +90,7 @@ public abstract class AbstractHttpServiceRegistrar implements
89
90
90
91
private @ Nullable BeanFactory beanFactory ;
91
92
92
- private final Map <String , HttpServiceGroup > groupMap = new LinkedHashMap <>();
93
+ private final Map <String , RegisteredGroup > groupMap = new LinkedHashMap <>();
93
94
94
95
private @ Nullable ClassPathScanningCandidateComponentProvider scanner ;
95
96
@@ -143,11 +144,11 @@ public final void registerBeanDefinitions(
143
144
144
145
mergeHttpServices (proxyRegistryBeanDef );
145
146
146
- this .groupMap .forEach ((groupName , group ) -> group .httpServiceTypes ().forEach (type -> {
147
+ this .groupMap .forEach ((groupName , group ) -> group .httpServiceTypeNames ().forEach (type -> {
147
148
GenericBeanDefinition proxyBeanDef = new GenericBeanDefinition ();
148
- proxyBeanDef .setBeanClass (type );
149
- proxyBeanDef .setInstanceSupplier (() -> getProxyInstance (proxyRegistryBeanName , groupName , type ));
149
+ proxyBeanDef .setBeanClassName (type );
150
150
String beanName = (groupName + "." + beanNameGenerator .generateBeanName (proxyBeanDef , beanRegistry ));
151
+ proxyBeanDef .setInstanceSupplier (() -> getProxyInstance (proxyRegistryBeanName , groupName , type ));
151
152
if (!beanRegistry .containsBeanDefinition (beanName )) {
152
153
beanRegistry .registerBeanDefinition (beanName , proxyBeanDef );
153
154
}
@@ -184,16 +185,16 @@ private void mergeHttpServices(GenericBeanDefinition proxyRegistryBeanDef) {
184
185
ConstructorArgumentValues args = proxyRegistryBeanDef .getConstructorArgumentValues ();
185
186
ConstructorArgumentValues .ValueHolder valueHolder = args .getArgumentValue (0 , Map .class );
186
187
Assert .state (valueHolder != null , "Expected Map constructor argument at index 0" );
187
- Map <String , HttpServiceGroup > targetMap = (Map <String , HttpServiceGroup >) valueHolder .getValue ();
188
+ Map <String , RegisteredGroup > targetMap = (Map <String , RegisteredGroup >) valueHolder .getValue ();
188
189
Assert .state (targetMap != null , "No constructor argument value" );
189
190
190
191
this .groupMap .forEach ((name , group ) -> {
191
- HttpServiceGroup previousGroup = targetMap .putIfAbsent (name , group );
192
+ RegisteredGroup previousGroup = targetMap .putIfAbsent (name , group );
192
193
if (previousGroup != null ) {
193
194
if (!compatibleClientTypes (group .clientType (), previousGroup .clientType ())) {
194
195
throw new IllegalArgumentException ("ClientType conflict for group '" + name + "'" );
195
196
}
196
- previousGroup .httpServiceTypes (). addAll ( group .httpServiceTypes ());
197
+ previousGroup .addHttpServiceTypeNames ( group .httpServiceTypeNames ());
197
198
}
198
199
});
199
200
}
@@ -206,14 +207,23 @@ private static boolean compatibleClientTypes(
206
207
clientTypeB == HttpServiceGroup .ClientType .UNSPECIFIED );
207
208
}
208
209
209
- private Object getProxyInstance (String registryBeanName , String groupName , Class <?> type ) {
210
+ private Object getProxyInstance (String registryBeanName , String groupName , String type ) {
210
211
Assert .state (this .beanFactory != null , "BeanFactory has not been set" );
211
212
HttpServiceProxyRegistry registry = this .beanFactory .getBean (registryBeanName , HttpServiceProxyRegistry .class );
212
- Object proxy = registry .getClient (groupName , type );
213
- Assert .notNull (proxy , "No proxy for HTTP Service [" + type . getName () + "]" );
213
+ Object proxy = registry .getClient (groupName , loadClass ( type ) );
214
+ Assert .notNull (proxy , "No proxy for HTTP Service [" + type + "]" );
214
215
return proxy ;
215
216
}
216
217
218
+ private static Class <?> loadClass (String type ) {
219
+ try {
220
+ return ClassUtils .forName (type , AbstractHttpServiceRegistrar .class .getClassLoader ());
221
+ }
222
+ catch (ClassNotFoundException ex ) {
223
+ throw new IllegalStateException ("Failed to load '" + type + "'" , ex );
224
+ }
225
+ }
226
+
217
227
218
228
/**
219
229
* Registry API to allow subclasses to register HTTP Services.
@@ -303,7 +313,7 @@ else if (defaultClientType != HttpServiceGroup.ClientType.UNSPECIFIED) {
303
313
304
314
@ Override
305
315
public GroupSpec register (Class <?>... serviceTypes ) {
306
- addHttpServiceTypes ( this . groupName , this . clientType , serviceTypes );
316
+ getOrCreateGroup ( groupName , clientType ). addHttpServiceTypes ( serviceTypes );
307
317
return this ;
308
318
}
309
319
@@ -325,29 +335,85 @@ public GroupSpec detectInBasePackages(String... packageNames) {
325
335
326
336
private void detect (String groupName , HttpServiceGroup .ClientType clientType , String packageName ) {
327
337
for (BeanDefinition definition : getScanner ().findCandidateComponents (packageName )) {
328
- String className = definition .getBeanClassName ();
329
- if (className != null ) {
330
- try {
331
- Class <?> clazz = ClassUtils .forName (className , getClass ().getClassLoader ());
332
- addHttpServiceTypes (groupName , clientType , clazz );
333
- }
334
- catch (ClassNotFoundException ex ) {
335
- throw new IllegalStateException ("Failed to load '" + className + "'" , ex );
336
- }
338
+ if (definition .getBeanClassName () != null ) {
339
+ getOrCreateGroup (groupName , clientType ).addHttpServiceTypeName (definition .getBeanClassName ());
337
340
}
338
341
}
339
342
}
340
343
341
- private void addHttpServiceTypes (
342
- String groupName , HttpServiceGroup .ClientType clientType , Class <?>... serviceTypes ) {
344
+ private RegisteredGroup getOrCreateGroup (String groupName , HttpServiceGroup .ClientType clientType ) {
345
+ return groupMap .computeIfAbsent (groupName , name -> new RegisteredGroup (name , clientType ));
346
+ }
347
+ }
348
+ }
349
+
350
+
351
+ /**
352
+ * A simple holder of registered HTTP Service type names, deferring the
353
+ * loading of classes until {@link #httpServiceTypes()} is called.
354
+ */
355
+ private static class RegisteredGroup implements HttpServiceGroup {
356
+
357
+ private final String name ;
358
+
359
+ private final Set <String > httpServiceTypeNames = new LinkedHashSet <>();
360
+
361
+ private final ClientType clientType ;
362
+
363
+ public RegisteredGroup (String name , ClientType clientType ) {
364
+ this .name = name ;
365
+ this .clientType = clientType ;
366
+ }
367
+
368
+ @ Override
369
+ public String name () {
370
+ return this .name ;
371
+ }
372
+
373
+ public Set <String > httpServiceTypeNames () {
374
+ return this .httpServiceTypeNames ;
375
+ }
343
376
344
- groupMap .computeIfAbsent (groupName , name -> new RegisteredGroup (name , new LinkedHashSet <>(), clientType ))
345
- .httpServiceTypes ().addAll (Arrays .asList (serviceTypes ));
377
+ @ Override
378
+ public Set <Class <?>> httpServiceTypes () {
379
+ return httpServiceTypeNames .stream ()
380
+ .map (AbstractHttpServiceRegistrar ::loadClass )
381
+ .collect (Collectors .toSet ());
382
+ }
383
+
384
+ @ Override
385
+ public ClientType clientType () {
386
+ return this .clientType ;
387
+ }
388
+
389
+ public void addHttpServiceTypes (Class <?>... httpServiceTypes ) {
390
+ for (Class <?> type : httpServiceTypes ) {
391
+ this .httpServiceTypeNames .add (type .getName ());
346
392
}
347
393
}
348
394
349
- private record RegisteredGroup (
350
- String name , Set <Class <?>> httpServiceTypes , ClientType clientType ) implements HttpServiceGroup {
395
+ public void addHttpServiceTypeNames (Collection <String > httpServiceTypeNames ) {
396
+ this .httpServiceTypeNames .addAll (httpServiceTypeNames );
397
+ }
398
+
399
+ public void addHttpServiceTypeName (String httpServiceTypeName ) {
400
+ this .httpServiceTypeNames .add (httpServiceTypeName );
401
+ }
402
+
403
+ @ Override
404
+ public final boolean equals (Object other ) {
405
+ return (other instanceof RegisteredGroup otherGroup && this .name .equals (otherGroup .name ));
406
+ }
407
+
408
+ @ Override
409
+ public int hashCode () {
410
+ return this .name .hashCode ();
411
+ }
412
+
413
+ @ Override
414
+ public String toString () {
415
+ return "RegisteredGroup[name='" + this .name + "', httpServiceTypes=" +
416
+ this .httpServiceTypeNames + ", clientType=" + this .clientType + "]" ;
351
417
}
352
418
}
353
419
0 commit comments