Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ There are several ways in which you can customize the `Application` class.
=== Customizing Scanning


By default Grails will scan all known source directories for controllers, domain class etc., however if there are packages in other JAR files you wish to scan you can do so by overriding the `packageNames()` method of the `Application` class:
Newly generated Grails applications include `@ComponentScan(value = 'your.application.package')` on the `Application` class. This scans standard Spring components in the application's base package and its subpackages.

Grails scans its known source directories separately for Grails artefacts such as controllers and domain classes. To add packages to that Grails artefact scan, override the `packageNames()` method of the `Application` class:

[source,groovy]
----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ import groovy.transform.CompileStatic
import io.micronaut.spring.boot.starter.EnableMicronaut

}
import org.springframework.context.annotation.ComponentScan
@if(features.contains("spring-boot-starter-security")) {
import org.springframework.context.annotation.Import

}


import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
@if(applicationType.equals(ApplicationType.PLUGIN) || applicationType.equals(ApplicationType.WEB_PLUGIN)) {
Expand All @@ -46,6 +48,7 @@ import grails.plugins.metadata.PluginSource
@@PluginSource
}
@@CompileStatic
@@ComponentScan(value = '@project.getPackageName()')
@if(features.contains("grails-micronaut")) {
@@EnableMicronaut
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class GrailsApplicationSpec extends BeanContextSpec implements CommandOutputFixt
output.containsKey("grails-app/init/example/grails/Application.${Language.GROOVY.extension}".toString())
def applicationGroovyFile = output.get("grails-app/init/example/grails/Application.${Language.GROOVY.extension}".toString())
applicationGroovyFile.contains("@CompileStatic")
applicationGroovyFile.contains("@ComponentScan(value = 'example.grails')")
!applicationGroovyFile.contains("@PluginSource")

where:
Expand All @@ -58,11 +59,26 @@ class GrailsApplicationSpec extends BeanContextSpec implements CommandOutputFixt
output.containsKey("grails-app/init/example/grails/Application.${Language.GROOVY.extension}".toString())
def applicationGroovyFile = output.get("grails-app/init/example/grails/Application.${Language.GROOVY.extension}".toString())
applicationGroovyFile.contains("@PluginSource")
applicationGroovyFile.contains("@ComponentScan(value = 'example.grails')")

where:
applicationType << [ApplicationType.PLUGIN, ApplicationType.WEB_PLUGIN]
}

void 'profile Application skeletons configure base-package component scanning'() {
given:
File profiles = findProfilesDirectory()

expect:
['base', 'plugin'].every { String profile ->
File application = new File(profiles, "${profile}/skeleton/grails-app/init/@grails.codegen.defaultPackage.path@/Application.groovy")
assert application.file, "missing profile Application skeleton ${application}"
assert application.text.contains('import org.springframework.context.annotation.ComponentScan')
Comment thread
jamesfredley marked this conversation as resolved.
assert application.text.contains("@ComponentScan(value = '@grails.codegen.defaultPackage@')")
true
}
}

void "REST-API application should have ApplicationController"() {
when:
def output = generate(ApplicationType.REST_API)
Expand Down Expand Up @@ -127,4 +143,13 @@ class GrailsApplicationSpec extends BeanContextSpec implements CommandOutputFixt
applicationType << ApplicationType.values().toList()

}

private static File findProfilesDirectory() {
File current = new File(GrailsApplicationSpec.getProtectionDomain().getCodeSource().getLocation().toURI())
while (current && !new File(current, 'grails-profiles').isDirectory()) {
current = current.parentFile
}
assert current != null: 'Unable to locate the grails-core repository root'
new File(current, 'grails-profiles')
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@

package org.grails.forge.create

import org.gradle.testkit.runner.TaskOutcome
import org.grails.forge.application.ApplicationType
import org.grails.forge.application.OperatingSystem
import org.grails.forge.options.DevelopmentReloading
import org.grails.forge.options.JdkVersion
import org.grails.forge.utils.CommandSpec
import spock.lang.Unroll

class CreateAppSpec extends CommandSpec {

Expand Down Expand Up @@ -60,72 +62,158 @@ class CreateAppSpec extends CommandSpec {
new File(dir, "grails-app/i18n").exists()
}

void "test create-app creates a correct Application.groovy"() {
@Unroll
void "test create-app #applicationType creates a correct Application.groovy"() {
given:
generateProject(OperatingSystem.MACOS_ARCH64, [], ApplicationType.DEFAULT_OPTION)
generateProject(OperatingSystem.MACOS_ARCH64, [], applicationType)
def applicationClassSourceFile = new File(dir, 'grails-app/init/example/grails/Application.groovy')

expect:
applicationClassSourceFile.exists()
applicationClassSourceFile.text == '''\
applicationClassSourceFile.text == applicationSource.stripIndent(8)

where:
applicationType | applicationSource
ApplicationType.WEB | '''\
package example.grails

import groovy.transform.CompileStatic

import org.springframework.context.annotation.ComponentScan

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration

@CompileStatic
@ComponentScan(value = 'example.grails')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
'''.stripIndent(8)
}
'''
ApplicationType.REST_API | '''\
package example.grails

void "test create-app with micronaut feature"() {
given:
// Micronaut features require JDK 25+ because micronaut-core's ScopedValues
// references java.lang.ScopedValue.CallableOp (JEP 506, finalized in JDK 25).
generateProject(OperatingSystem.MACOS_ARCH64, ['grails-micronaut'], ApplicationType.WEB,
DevelopmentReloading.DEFAULT_OPTION, JdkVersion.JDK_25)
import groovy.transform.CompileStatic

def gradleProperties = new File(dir, 'gradle.properties')
def gradleBuildFile = new File(dir, 'build.gradle')
import org.springframework.context.annotation.ComponentScan

expect:
gradleProperties.exists()
gradleProperties.text.contains('micronautPlatformVersion=4.10.16')
gradleBuildFile.exists()
gradleBuildFile.text.contains('implementation "org.apache.grails:grails-micronaut"')
}
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration

void "test create-app web-plugin creates a correct Application.groovy"() {
given:
generateProject(OperatingSystem.MACOS_ARCH64, [], ApplicationType.WEB_PLUGIN)
@CompileStatic
@ComponentScan(value = 'example.grails')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
'''
ApplicationType.PLUGIN | '''\
package example.grails

def applicationClassSourceFile = new File(dir, 'grails-app/init/example/grails/Application.groovy')
import groovy.transform.CompileStatic

expect:
applicationClassSourceFile.exists()
applicationClassSourceFile.text == '''\
import org.springframework.context.annotation.ComponentScan

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import grails.plugins.metadata.PluginSource

@PluginSource
@CompileStatic
@ComponentScan(value = 'example.grails')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
'''
ApplicationType.WEB_PLUGIN | '''\
package example.grails

import groovy.transform.CompileStatic

import org.springframework.context.annotation.ComponentScan

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import grails.plugins.metadata.PluginSource

@PluginSource
@CompileStatic
@ComponentScan(value = 'example.grails')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
'''.stripIndent(8)
'''
}

void "test generated application scans standard Spring components"() {
given:
generateProject(OperatingSystem.MACOS_ARCH64)
File componentSourceFile = new File(dir, 'src/main/groovy/example/grails/components/ScannedComponent.groovy')
componentSourceFile.parentFile.mkdirs()
componentSourceFile.text = '''\
package example.grails.components

import org.springframework.stereotype.Component

@Component
class ScannedComponent {
String value() {
'scanned'
}
}
'''.stripIndent()
File componentSpecFile = new File(dir, 'src/test/groovy/example/grails/ComponentScanningSpec.groovy')
componentSpecFile.parentFile.mkdirs()
componentSpecFile.text = '''\
package example.grails

import example.grails.components.ScannedComponent
import grails.testing.mixin.integration.Integration
import org.springframework.beans.factory.annotation.Autowired
import spock.lang.Specification

@Integration
class ComponentScanningSpec extends Specification {

@Autowired
ScannedComponent scannedComponent

void "standard Spring component is injected"() {
expect:
scannedComponent.value() == 'scanned'
}
}
'''.stripIndent()

when:
def result = executeGradle('test', '--tests', 'example.grails.ComponentScanningSpec')

then:
result.task(':test').outcome == TaskOutcome.SUCCESS
}

void "test create-app with micronaut feature"() {
given:
// Micronaut features require JDK 25+ because micronaut-core's ScopedValues
// references java.lang.ScopedValue.CallableOp (JEP 506, finalized in JDK 25).
generateProject(OperatingSystem.MACOS_ARCH64, ['grails-micronaut'], ApplicationType.WEB,
DevelopmentReloading.DEFAULT_OPTION, JdkVersion.JDK_25)

def gradleProperties = new File(dir, 'gradle.properties')
def gradleBuildFile = new File(dir, 'build.gradle')

expect:
gradleProperties.exists()
gradleProperties.text.contains('micronautPlatformVersion=4.10.16')
gradleBuildFile.exists()
gradleBuildFile.text.contains('implementation "org.apache.grails:grails-micronaut"')
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package @grails.codegen.defaultPackage@

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.context.annotation.ComponentScan

import groovy.transform.CompileStatic

@CompileStatic
@ComponentScan(value = '@grails.codegen.defaultPackage@')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package @grails.codegen.defaultPackage@
import grails.boot.*
import grails.boot.config.GrailsAutoConfiguration
import grails.plugins.metadata.*
import org.springframework.context.annotation.ComponentScan

@PluginSource
@ComponentScan(value = '@grails.codegen.defaultPackage@')
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
}