@@ -204,27 +204,53 @@ if (subDir.isDirectory()) projectDir = subDir
204204// ─── Spring configuration class generator ─────────────────────────────────────
205205// When includeSpring is true, every module the app composes carries a @Configuration
206206// class in its `.config` sub-package (the app's Application class @Imports them all)
207- // and declares spring-context. Everything here is skipped when includeSpring is false.
207+ // and declares spring-context. The module root package also gets a marker
208+ // "{Module}ComponentScan" interface that the @Configuration targets via
209+ // @ComponentScan(basePackageClasses=…) — a type-safe anchor for scanning the whole
210+ // module. Everything here is skipped when includeSpring is false.
208211
209212def SPRING_CONTEXT = [groupId : ' org.springframework' , artifactId : ' spring-context' ]
210213def springCtx = includeSpring ? [SPRING_CONTEXT ] : [] // appended to module deps only when Spring is enabled
211214def configFqns = []
212215
213- /* * Writes a @Configuration class into {module}/…/{mainSub}/config and records its FQN; no-op when Spring is off. */
216+ /* * Writes a {Module}ComponentScan marker interface into the module root package and a
217+ * @Configuration class (anchored to it via @ComponentScan) into {module}/…/{mainSub}/config,
218+ * recording the config FQN; no-op when Spring is off. */
214219def configClass = { String module , String mainSub ->
215220 if (! includeSpring) return null
216- def className = module. split(' -' ). collect { it. capitalize() }. join(' ' ) + ' Configuration'
221+ def baseName = module. split(' -' ). collect { it. capitalize() }. join(' ' )
222+ def className = baseName + ' Configuration'
223+ def scanName = baseName + ' ComponentScan'
224+
225+ // Marker interface in the module root package — the @ComponentScan basePackageClasses anchor.
226+ def rootPkgFq = (pkgPath + ' /' + mainSub). replace(' /' , ' .' )
227+ writeFile(projectDir, " ${ module} /src/main/java/${ pkgPath} /${ mainSub} /${ scanName} .java" , """ \
228+ package ${ rootPkgFq} ;
229+
230+ /**
231+ * Anchor class for based package class scanning.
232+ */
233+ public interface ${ scanName} {
234+ }
235+ """ )
236+
217237 def pkgFq = (pkgPath + ' /' + mainSub + ' /config' ). replace(' /' , ' .' )
218238 def dir = " ${ module} /src/main/java/${ pkgPath} /${ mainSub} /config"
239+ def imports = [
240+ " import ${ rootPkgFq} .${ scanName} ;" ,
241+ ' import org.springframework.context.annotation.ComponentScan;' ,
242+ ' import org.springframework.context.annotation.Configuration;' ,
243+ ]. sort(). join(' \n ' )
219244 writeFile(projectDir, " ${ dir} /${ className} .java" , """ \
220245package ${ pkgFq} ;
221246
222- import org.springframework.context.annotation.Configuration;
247+ ${ imports }
223248
224249/**
225250 * Spring configuration for the ${ module} module.
226251 */
227252@Configuration
253+ @ComponentScan(basePackageClasses = ${ scanName} .class)
228254public class ${ className} {
229255}
230256""" )
0 commit comments