Package groovy.junit6.plugin

# Annotation Interface ForkedJvm

@Documented @Incubating @Retention(RUNTIME) @Target({TYPE,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

- ## Optional Element Summary

  Optional Elements
  Modifier and Type
  Optional Element
  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.

- ## Element Details

  - ### systemProperties

    String[] systemProperties
    System properties to set on the forked JVM, each as a `"key=value"` string.
    Default:
      {}

  - ### jvmArgs

    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:
      {}

  - ### inheritProperties

    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:
      {}

  - ### excludeFromClasspath

    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. `lib/*`), and `Class-Path:` manifest entries inherited from another jar are not matched.

    Default:
      {}