Package: groovy.junit6.plugin

## [Java] Annotation Type ForkedJvm

- groovy.junit6.plugin.ForkedJvm

-     @Documented
      @Incubating
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ElementType.TYPE, ElementType.METHOD})
      @ExtendWith(ForkedJvmExtension.class)
      public @interface ForkedJvm

  Runs the annotated test method (or every test method on the annotated class) in a freshly forked JVM, optionally configured with extra system properties and JVM arguments.

  Useful for testing behaviour gated by JVM startup state that cannot be toggled at runtime, e.g. `static final` fields initialised from `System.getProperty(...)` at class load time (such as `groovy.val.enabled`).

  System properties are supplied as `"key=value"` strings:

       @Test
       @ForkedJvm(systemProperties = {"groovy.val.enabled=false"})
       void runsInChildJvm() {
           assert System.getProperty("groovy.val.enabled").equals("false");
       }

  JVM arguments are passed verbatim:

       @Test
       @ForkedJvm(jvmArgs = {"--add-opens=java.base/java.lang=ALL-UNNAMED"})
       void withModuleAccess() { ... }

  Recipe — `@GrabConfig(systemClassLoader=true)` tests: scripts that use `@GrabConfig(systemClassLoader=true)` to add resolved JARs to the JVM system classloader only behave correctly when that classloader is Groovy's `RootLoader`, which cannot be retrofitted after JVM startup. Set it via `jvmArgs`:

       @Test
       @ForkedJvm(jvmArgs = {"-Djava.system.class.loader=org.codehaus.groovy.tools.RootLoader"})
       void scriptUsesGrabConfigSystemClassLoader() {
           assertScript '''
               @GrabConfig(systemClassLoader=true)
               @Grab('org.example:some-lib:1.0')
               // ... library is now visible to anything resolving via the system classloader ...
           '''
       }

  Properties from the parent JVM can be propagated to the child via inheritProperties(). Each entry is either an exact property name or a prefix pattern ending in `*`. This is useful when the parent test JVM is configured by the build (e.g. Gradle) with a property the child also needs, such as Spock's Groovy-version-check override:

       @Test
       @ForkedJvm(inheritProperties = {"spock.*"})
       void seesSpockOverride() { ... }

  Lifecycle gotcha: JUnit lifecycle hooks (`@BeforeAll`, `@BeforeEach`, `@AfterAll`, `@AfterEach`) fire in both the parent and the forked child JVM, because the child re-runs the class lifecycle for the targeted method. Setup that mutates JVM-global state — typically `System.setProperty(...)` — therefore replays in the child and can defeat tests that assert on what was (or was not) propagated across the fork. Guard parent-only setup with the forked-flag check:

       @BeforeAll
       static void setUp() {
           if (Boolean.parseBoolean(System.getProperty("groovy.junit6.forked"))) return;
           // ...parent-only setup here...
       }

  Since:
    6.0.0

- - ### Element Summary

    Optional Element Summary
    Type | Name and Description
    --- | ---
    `String[]` | `excludeFromClasspath` Regular expressions that exclude matching entries from the parent's `java.class.path` when constructing the forked JVM's classpath.
    `String[]` | `inheritProperties` Names or prefix patterns of system properties from the parent JVM to propagate to the forked child.
    `String[]` | `jvmArgs` Raw JVM arguments to prepend to the forked JVM's command line, e.g.
    `String[]` | `systemProperties` System properties to set on the forked JVM, each as a `"key=value"` string.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Element Detail

    - #### public String[] excludeFromClasspath

      Regular expressions that exclude matching entries from the parent's `java.class.path` when constructing the forked JVM's classpath. Each pattern is applied to each path entry with Matcher.find, so plain substrings (e.g. `"junit-platform-instrumentation"`) work without anchoring.

      Patterns can also be supplied via the system property `groovy.junit6.forked.excludeClasspath` (comma-separated) for build- or CI-level configuration without modifying test source. Annotation values and the system-property values are unioned.

      Limitations: this filter only inspects entries appearing literally in `java.class.path`. Modules on `--module-path`, directory wildcards (e.g. {@code lib/*}), and `Class-Path:` manifest entries inherited from another jar are not matched.

      Default:
        {}

    - #### public String[] inheritProperties

      Names or prefix patterns of system properties from the parent JVM to propagate to the forked child. Each entry is either an exact property name (e.g. `"spock.iKnowWhatImDoing.disableGroovyVersionCheck"`) or a prefix pattern ending in `*` (e.g. `"spock.*"` or `"groovy.compiler.*"`). Patterns that match no parent property are silently ignored.

      Properties supplied via systemProperties() override inherited values for the same key.

      Default:
        {}

    - #### public String[] jvmArgs

      Raw JVM arguments to prepend to the forked JVM's command line, e.g. `"-Xmx128m"` or `"--add-opens=java.base/java.lang=ALL-UNNAMED"`.

      Default:
        {}

    - #### public String[] systemProperties

      System properties to set on the forked JVM, each as a `"key=value"` string.

      Default:
        {}