Package: groovy.transform.stc

## [Java] Annotation Type ClassTag

- groovy.transform.stc.ClassTag

-     @Documented
      @Incubating
      @Retention(RetentionPolicy.RUNTIME)
      @Target(ElementType.PARAMETER)
      public @interface ClassTag

  Parameter annotation marking a `Class` parameter as compiler-supplied under static compilation. On the JVM, a method that needs the runtime type of a generic type parameter cannot recover it (erasure), so the API must take an explicit `Class<T>` token. That token is redundant with a type the compiler already knows — the receiver's type argument. `@ClassTag` removes the redundancy.

  Under `@CompileStatic` / `@TypeChecked`, when a call omits the `Class` token argument(s), the type checker may select an overload whose parameters, beyond those matching the supplied arguments, are all `@ClassTag Class<X>` and synthesise the `X.class` argument(s) from the receiver's matching type argument(s), rewriting the call. Each `@ClassTag` parameter is filled at its declared position — anywhere in the parameter list, not just trailing — and the caller's supplied arguments map to the remaining (non-tag) parameters in order.

  As an example, `asChecked` declares an explicit token:

       public static <T> List<T> asChecked(List<T> self, @ClassTag Class<T> type)

  which lets statically-typed callers omit it:

       List<String> list = [].asChecked()      // compiler injects String.class

  Selection is normally additive: the tagged overload is chosen only when the call as written matches no method (as above — there is no token-less `asChecked()`). When a token-less overload also matches, choosing the tagged one instead (preemption) changes the meaning of existing source, so three conditions gate it:

  - Intent — the API author must declare the tagged overload preemptive with preempt=true; without it the overload is only ever selected additively. Groovy's own checked `withDefault` overloads declare it (their lenient sibling predates them and could silently corrupt a typed map's key set).
  - Containment — a tagged overload may only preempt a token-less overload declared by the same class (or, for instance methods, the same class hierarchy). A library can upgrade callers of its own lenient API but can never capture calls owned by another library, so adding a jar to the compile classpath cannot re-route existing calls it does not already own.
  - Consent — the consumer may veto all preemption globally via CompilerConfiguration.setClassTagPreemptionDisabled (also seeded from the `groovy.classtag.preemption.disable` system property). Code compiled with the veto behaves exactly as it did before any library declared preemption; a finer-grained (per-method or per-call-site) opt-out may be added later if experience shows the need.

  Boundaries:

  - Static only. Dynamic Groovy ignores the annotation and binds the original overload; the shorter (token-less) spelling is static-only syntax. If no token can be synthesised there is no zero-token method to bind, so the call fails to resolve.
  - The type variable must be statically known. `List<String>` works; `def`, raw `List`, and wildcard-only types do not — no token is synthesised.
  - Receiver type arguments only. A type variable declared by the method itself (which shadows any like-named class variable) cannot be reified from the receiver; tagging one on an instance method compiled from source is a compile-time error. Static methods are exempt: in the extension-method authoring pattern the type variable is necessarily method-declared and connects to the receiver through the self parameter.
  - Erased fidelity. The synthesised `Class<X>` reifies only the erased class: `List<String>` and `List<Integer>` are indistinguishable.
  - Nothing-to-gain guard. When every token would erase to `Object` (e.g. a `List<Object>` receiver), no token is synthesised — a checked `Object` view could never reject anything — so an additive call fails to resolve and a preemptive upgrade is skipped (the lenient overload is kept).
  - Escape hatch. Passing the `Class` explicitly always works, in every mode.
  Since:
    6.0.0

- - ### Element Summary

    Optional Element Summary
    Type | Name and Description
    --- | ---
    `boolean` | `preempt` Declares that the overload carrying this parameter may preempt a matching token-less overload declared by the same class (or class hierarchy): an existing call that binds the token-less overload is transparently upgraded to this one under static compilation.
    `String` | `value` Optionally names the type variable to reify, for when the parameter type cannot carry it (e.g. a raw or wildcard `Class` token, or a method whose own type variables do not line up with the receiver's).

  - ### Inherited Methods Summary

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

- - ### Element Detail

    - #### public boolean preempt

      Declares that the overload carrying this parameter may preempt a matching token-less overload declared by the same class (or class hierarchy): an existing call that binds the token-less overload is transparently upgraded to this one under static compilation. Because that changes the meaning of existing source, it is off by default; without it the overload is only selected additively (when the call as written matches no method). Consumers retain a veto via CompilerConfiguration.setClassTagPreemptionDisabled. By convention, set it on every `@ClassTag` parameter of the overload (any one suffices to declare the intent).

      Returns:
        whether this overload may preempt its same-owner token-less sibling
      Default:
        false

    - #### public String value

      Optionally names the type variable to reify, for when the parameter type cannot carry it (e.g. a raw or wildcard `Class` token, or a method whose own type variables do not line up with the receiver's). When empty (the default), the type variable is read from the parameter type `Class<X>`.

      Note: `for` is a Java reserved word and cannot be an annotation member name, so the override is spelled `@ClassTag("K")` (or `@ClassTag(value = "K")`). For a method compiled from source in the same unit, the static type checker rejects a name that does not resolve to a type variable in scope, so typos fail at compile time. The check cannot reach an extension method supplied by an already-compiled library (it is never visited as source); such a typo silently disables injection rather than being reported.

      Returns:
        the name of the type variable to reify, or empty to read it from the parameter type
      Default:
        ""