Class BuildModeProcessor

java.lang.Object
javax.annotation.processing.AbstractProcessor
com.cloudforge.core.buildmode.BuildModeProcessor
All Implemented Interfaces:
Processor

@SupportedAnnotationTypes("*") @SupportedOptions({"cfc.buildmode.value","cfc.buildmode.targetClass"}) @SupportedSourceVersion(RELEASE_25) public final class BuildModeProcessor extends AbstractProcessor
Bakes a compile-time constant into a generated class from a single -A compiler option, so a build-time fact (which Maven profile compiled these sources) survives into the compiled artifact as a real static final field — not something a caller can influence by how the resulting binary is later invoked.

This exists because a runtime heuristic doing the equivalent job (distinguishing "packaged production build" from "running from source" by inspecting the current ClassLoader's class name) stops meaning what it's supposed to mean the moment an artifact ships as an ahead-of-time-compiled native image: there is no packaging-specific classloader in a native image to detect at all, so that kind of check silently collapses to always-true inside the real shipped binary. A value fixed at compile time has no equivalent failure mode — it's a constant in the generated bytecode, evaluated once, at the moment the option is passed to javac, not re-derived from anything observable or influenceable at runtime.

Registered as a real Processor in this module's own META-INF/services — any consumer already depending on this artifact can put it on its annotation processor path with no separate module or extra dependency. Generic on purpose: this class has no knowledge of what the baked value is used for, only how to bake one in.

Emits its generated file on the very first round, not on RoundEnvironment.processingOver(): generating a new type during the last round is invalid per Filer.createSourceFile(CharSequence, Element...)'s own contract (javac warns "will not be subject to annotation processing" and doesn't reliably compile it into the same pass). The first round is guaranteed to happen exactly once before any dependent source is compiled, and this processor doesn't need to observe anything from other rounds, so there's no reason to wait for the last one.

  • Field Details

    • OPTION

      public static final String OPTION
      -A option carrying the baked value, "true"/"false" (case-sensitive, matching Boolean.parseBoolean(String)'s own contract, deliberately not more lenient than that — an unrecognized value should fail the build, not silently parse as false).
      See Also:
    • TARGET_CLASS_OPTION

      public static final String TARGET_CLASS_OPTION
      -A option naming the fully-qualified generated class, e.g. com.cloudforgeci.manager.generated.BuildProvenance. Required, not defaulted: a processor silently picking its own package/class name for every consumer would be a worse surprise than requiring one explicit line per consumer's build.
      See Also:
  • Constructor Details

    • BuildModeProcessor

      public BuildModeProcessor()
  • Method Details