////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////


==== GrailsCompileStatic


The `GrailsCompileStatic` annotation may be applied to a class or methods within a class.

[source,groovy]
----
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
class SomeClass {

    // all of the code in this class will be statically compiled

    def methodOne() {
        // ...
    }

    def methodTwo() {
        // ...
    }

    def methodThree() {
        // ...
    }
}
----


[source,groovy]
----
import grails.compiler.GrailsCompileStatic

class SomeClass {

    // methodOne and methodThree will be statically compiled
    // methodTwo will be dynamically compiled

    @GrailsCompileStatic
    def methodOne() {
        // ...
    }

    def methodTwo() {
        // ...
    }

    @GrailsCompileStatic
    def methodThree() {
        // ...
    }
}
----

It is possible to mark a class with `GrailsCompileStatic` and exclude specific methods by marking them with `GrailsCompileStatic` and specifying that the type checking should be skipped for that particular method as shown below.


[source,groovy]
----
import grails.compiler.GrailsCompileStatic
import groovy.transform.TypeCheckingMode

@GrailsCompileStatic
class SomeClass {

    // methodOne and methodThree will be statically compiled
    // methodTwo will be dynamically compiled

    def methodOne() {
        // ...
    }

    @GrailsCompileStatic(TypeCheckingMode.SKIP)
    def methodTwo() {
        // ...
    }

    def methodThree() {
        // ...
    }
}
----

Code that is marked with `GrailsCompileStatic` will all be statically compiled except for Grails specific interactions that cannot be statically compiled but that `GrailsCompileStatic` can identify as permissible for dynamic dispatch.  These include things like invoking dynamic finders and DSL code in configuration blocks like constraints and mapping closures in domain classes.

Care must be taken when deciding to statically compile code.  There are benefits associated with static compilation but in order to take advantage of those benefits you are giving up the power and flexibility of dynamic dispatch.  For example if code is statically compiled it cannot take advantage of runtime metaprogramming enhancements which may be provided by plugins.

===== Tag Library Calls in Controllers

Controllers annotated with `@GrailsCompileStatic` can invoke tag library methods without compile errors.
Tag dispatch is handled at runtime through `TagLibraryInvoker`, and `@GrailsCompileStatic` includes a built-in type-checking extension that recognises these call sites and allows them to compile.

Both calling patterns work:

[source,groovy]
----
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
class BookController {

    def index() {
        // Direct call — tag in the default namespace invoked on `this`
        response.writer << link(controller: 'book', action: 'list')

        // Namespaced call — namespace dispatcher property, then tag method
        response.writer << g.message(code: 'book.list.title')
    }
}
----

Only controller classes (those whose name ends with `Controller`) receive this treatment.
All other code in the controller remains fully type-checked.
If you need to opt a single method out of static compilation, use `@GrailsCompileStatic(TypeCheckingMode.SKIP)` on that method.

===== Applying GrailsCompileStatic Across All Controllers, Services and Tag Libraries

Rather than annotating each class individually, static compilation can be enabled for every controller, service and tag library in an application. The Grails Gradle plugin exposes these opt-ins in the nested `compileStatic` block of the `grails` build configuration:

[source,groovy]
.build.gradle
----
grails {
    compileStatic {
        controllers = true   // compile every grails-app/controllers class with @GrailsCompileStatic
        services = true      // compile every grails-app/services class with @GrailsCompileStatic
        tagLibs = true       // compile every grails-app/taglib class with @GrailsCompileStatic
    }
}
----

The options are lazy properties that are read when the Groovy compile task runs, so they may be configured from anywhere in the build regardless of ordering. All three are disabled by default and are independent, so each artefact type can be enabled on its own. To turn them all on at once, use the `all` shortcut instead:

[source,groovy]
.build.gradle
----
grails {
    compileStatic {
        all = true     // shortcut for controllers + services + tag libraries
    }
}
----

When an opt-in is enabled, every matching artefact is compiled exactly as if it were annotated with `@GrailsCompileStatic`, including the Grails-specific dispatch that the annotation already permits — dynamic finders, constraints and mapping DSLs, and tag library calls in both controllers and tag libraries.

[NOTE]
====
For tag libraries, define tags as methods (for example `def myTag(Map attrs, Closure body)`). A tag library that still declares tags the deprecated way — as closure fields (`def myTag = { attrs, body -> }`) — cannot be statically compiled when it dispatches to other tags, so the `tagLibs` opt-in automatically skips it: it is left dynamically compiled and a build warning is emitted. Migrate such a tag library to method-based tags to opt it in, or annotate it with `@GrailsCompileStatic` to force static compilation regardless.
====

An individual class always wins over the build-wide default by declaring its own compilation annotation. A class annotated with `@CompileDynamic` (or `@GrailsCompileStatic`, `@CompileStatic`, `@GrailsTypeChecked` or `@TypeChecked`) keeps its own setting and is never overridden by the opt-in:

[source,groovy]
----
import groovy.transform.CompileDynamic

@CompileDynamic
class LegacyController {
    // compiled dynamically even when compileStatic { controllers = true } is enabled
}
----

As with any move to static compilation, enabling these options trades the flexibility of dynamic dispatch (such as runtime metaprogramming contributed by plugins) for the benefits of static compilation. Introduce them incrementally and rely on the per-class opt-out for code that still needs dynamic behaviour.