Skip to content

Preload org.jetbrains.annotations.{NotNull,Nullable} in MyJavaFileManager #177

Description

@davido

Symptom

Starting on JDK 25, any downstream user of chronicle-values' runtime code generation (ValueModel.nativeClass() / heapClass()) fails at the first compile with:

      com.sun.tools.javac.code.Symbol$CompletionFailure:
          class file for NotNull not found

Caused by chronicle bytecode (chronicle-bytes / chronicle-core / others) carrying constant-pool references to org.jetbrains.annotations.NotNull and Nullable on inherited method signatures. javac walks the full compile model, tries to resolve the symbol, and fails when the annotation class file is not on its classpath.

JDK 21 silently tolerated the missing symbol. JDK 25 (and seemingly also recent JDK 24 builds) tightened annotation symbol resolution and now fail symbol completion outright.

Why this is hard to work around downstream

Chronicle calls CACHED_COMPILER.loadFromJava(cl, ...) with the value type's classloader. For embedding hosts where value types live in one classloader (e.g. the application's) but the JetBrains annotations jar is only visible in another (e.g. a plugin classloader), the compiler's classpath search never reaches the plugin classloader. Bundling the annotation jar into the plugin helps nothing; neither does CACHED_COMPILER.updateFileManagerForClassLoader(...) because:

  • The hook is a silent no-op before the first compile per classloader (fileManagerMap.get(cl) returns null).
  • Chronicle-values uses the hook to register the value type, not the JetBrains annotation classes.

The only working downstream fix today is CompilerUtils.addClassPath(jarPath) from application startup, which mutates the global compiler classpath -- not great ownership-wise for downstream plugins.

Proposed fix

Add org.jetbrains.annotations.NotNull and Nullable to the static dependencyFileObjects preload in net.openhft.chronicle.values.MyJavaFileManager (the block that already preloads Chronicle's own annotations like Align, Array, Group, MaxUtf8Length, Range, and chronicle's internal NotNull):

// MyJavaFileManager.java -- existing block around line 49
Arrays.asList(
        // ... existing entries ...
        Align.class, Array.class, Group.class, MaxUtf8Length.class,
        net.openhft.chronicle.values.NotNull.class, Range.class,

        // ADD:
        org.jetbrains.annotations.NotNull.class,
        org.jetbrains.annotations.Nullable.class,

        // ... rest ...
).forEach(c -> addFileObjects(dependencyFileObjects, c));

Doing this in chronicle-values eliminates the failure for every downstream user on JDK 25+ -- bundling, classpath mutation, and file-manager hooks all become unnecessary for the JetBrains-annotation case specifically.

The org.jetbrains:annotations artifact would need to move out of provided scope (or chronicle-values would need to pin and bundle it for its own runtime-compiler purposes), since the static block references its .class literals.

Repro

  • Java 25 (Temurin/Zulu/etc., 25.0.x).
  • Any chronicle-values consumer that compiles value types whose interface hierarchy carries @NotNull on inherited methods -- e.g. Gerrit's cache-chroniclemap plugin against value types defined in Gerrit core. Stack trace:

ValueModel.createClass -> CachedCompiler.loadFromJava -> ... -> Symbol$CompletionFailure.

Versions

  • chronicle-values 2.25ea4 through 2026.2 (current latest BOM) exhibit the issue.
  • chronicle-values 2.26.4+ added updateFileManagerForClassLoader, but that hook does not resolve this specific failure (registers value type, not annotations).

Related

  • chronicle-map#289 (decision to mark org.jetbrains:annotations as provided) is correct for normal library consumers, but bites runtime-codegen users on JDK 25+.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions