1616
1717package org .springframework .web .service .registry ;
1818
19+ import java .util .Arrays ;
20+ import java .util .function .Consumer ;
21+
22+ import org .jspecify .annotations .Nullable ;
23+
24+ import org .springframework .beans .BeanUtils ;
25+ import org .springframework .beans .factory .annotation .AnnotatedBeanDefinition ;
26+ import org .springframework .beans .factory .config .BeanDefinition ;
1927import org .springframework .core .annotation .MergedAnnotation ;
28+ import org .springframework .core .io .ResourceLoader ;
2029import org .springframework .core .type .AnnotationMetadata ;
30+ import org .springframework .core .type .classreading .CachingMetadataReaderFactory ;
31+ import org .springframework .core .type .classreading .MetadataReader ;
32+ import org .springframework .core .type .classreading .MetadataReaderFactory ;
33+ import org .springframework .util .Assert ;
2134import org .springframework .util .ClassUtils ;
2235import org .springframework .util .ObjectUtils ;
36+ import org .springframework .util .StringUtils ;
37+ import org .springframework .util .function .ThrowingFunction ;
38+ import org .springframework .web .service .registry .HttpServiceGroup .ClientType ;
2339
2440/**
2541 * Built-in implementation of {@link AbstractHttpServiceRegistrar} that uses
3349 */
3450class ImportHttpServiceRegistrar extends AbstractHttpServiceRegistrar {
3551
52+ private @ Nullable MetadataReaderFactory metadataReaderFactory ;
53+
54+ @ Override
55+ public void setResourceLoader (ResourceLoader resourceLoader ) {
56+ super .setResourceLoader (resourceLoader );
57+ this .metadataReaderFactory = new CachingMetadataReaderFactory (resourceLoader );
58+ }
59+
3660 @ Override
3761 protected void registerHttpServices (GroupRegistry registry , AnnotationMetadata metadata ) {
3862
@@ -50,7 +74,7 @@ protected void registerHttpServices(GroupRegistry registry, AnnotationMetadata m
5074 private void processImportAnnotation (MergedAnnotation <?> annotation , GroupRegistry groupRegistry ,
5175 AnnotationMetadata metadata ) {
5276
53- String groupName = annotation . getString ( "group" );
77+ ImportHttpServices . GroupProvider groupProvider = getGroupProvider ( annotation );
5478 HttpServiceGroup .ClientType clientType = annotation .getEnum ("clientType" , HttpServiceGroup .ClientType .class );
5579 Class <?>[] types = annotation .getClassArray ("types" );
5680 Class <?>[] basePackageClasses = annotation .getClassArray ("basePackageClasses" );
@@ -60,10 +84,70 @@ private void processImportAnnotation(MergedAnnotation<?> annotation, GroupRegist
6084 basePackages = new String [] { ClassUtils .getPackageName (metadata .getClassName ()) };
6185 }
6286
63- groupRegistry .forGroup (groupName , clientType )
64- .register (types )
65- .detectInBasePackages (basePackageClasses )
66- .detectInBasePackages (basePackages );
87+ registerHttpServices (groupRegistry , groupProvider , clientType , types , basePackageClasses , basePackages );
88+ }
89+
90+ private ImportHttpServices .GroupProvider getGroupProvider (MergedAnnotation <?> annotation ) {
91+ String group = annotation .getString ("group" );
92+ Class <?> groupProvider = annotation .getClass ("groupProvider" );
93+ if (groupProvider == ImportHttpServices .GroupProvider .class ) {
94+ return new FixedGroupProvider (StringUtils .hasText (group ) ? group : HttpServiceGroup .DEFAULT_GROUP_NAME );
95+ }
96+ Assert .state (!StringUtils .hasText (group ), "'group' cannot be mixed with 'groupProvider'" );
97+ return (ImportHttpServices .GroupProvider ) BeanUtils .instantiateClass (groupProvider );
98+ }
99+
100+ private void registerHttpServices (GroupRegistry groupRegistry ,
101+ ImportHttpServices .GroupProvider groupProvider , ClientType clientType , Class <?>[] types ,
102+ Class <?>[] basePackageClasses , String [] basePackages ) {
103+
104+ if (groupProvider instanceof FixedGroupProvider fixedGroupProvider ) {
105+ String groupName = fixedGroupProvider .group ();
106+ groupRegistry .forGroup (groupName , clientType )
107+ .register (types )
108+ .detectInBasePackages (basePackageClasses )
109+ .detectInBasePackages (basePackages );
110+ }
111+ else {
112+ MetadataReaderFactory metadataReaderFactory = (this .metadataReaderFactory != null ) ?
113+ this .metadataReaderFactory : new CachingMetadataReaderFactory ();
114+
115+ Consumer <AnnotationMetadata > register = metadata -> {
116+ String group = groupProvider .group (metadata );
117+ if (group != null ) {
118+ groupRegistry .forGroup (group , clientType ).registerTypeNames (metadata .getClassName ());
119+ }
120+ };
121+
122+ Arrays .stream (types )
123+ .map (Class ::getName )
124+ .map (ThrowingFunction .of (metadataReaderFactory ::getMetadataReader ))
125+ .map (MetadataReader ::getAnnotationMetadata )
126+ .forEach (register );
127+ Arrays .stream (basePackageClasses )
128+ .map (Class ::getPackageName )
129+ .flatMap (this ::findHttpServices )
130+ .map (this ::getMetadata )
131+ .forEach (register );
132+ Arrays .stream (basePackages )
133+ .flatMap (this ::findHttpServices )
134+ .map (this ::getMetadata )
135+ .forEach (register );
136+ }
137+ }
138+
139+ private AnnotationMetadata getMetadata (BeanDefinition beanDefinition ) {
140+ Assert .state (beanDefinition instanceof AnnotatedBeanDefinition ,
141+ "AnnotatedBeanDefinition required when using 'groupProvider'" );
142+ return ((AnnotatedBeanDefinition ) beanDefinition ).getMetadata ();
143+ }
144+
145+ private static record FixedGroupProvider (String group ) implements ImportHttpServices .GroupProvider {
146+
147+ @ Override
148+ public String group (AnnotationMetadata metadata ) {
149+ return this .group ;
150+ }
67151 }
68152
69153}
0 commit comments