J2CL’s javac frontend configures SOURCE_OUTPUT when annotation processing is enabled, but does not configure CLASS_OUTPUT.
This affects annotation processors that use the standard API to create a class-output resource with an originating element:
processingEnv
.getFiler()
.createResource(
StandardLocation.CLASS_OUTPUT,
"",
"META-INF/example/config.json",
originatingElement);
On JDK 18 and later, javac propagates the originating element’s source file to the JavaFileManager as an originating file. When CLASS_OUTPUT has not been configured, javac may use that source file as the sibling placement hint.
Observed with JDK 21.0.9:
- With only
SOURCE_OUTPUT configured, the resource is written beside the originating source input.
- The directory portion of the requested resource name is lost because javac’s sibling fallback uses the basename.
- If the source path traverses a symlink, the write can cross that symlink and modify the underlying source tree.
- The file is not a declared J2CL action output, so cached action results can hide the side effect.
- Configuring
CLASS_OUTPUT causes the complete resource path to be written beneath that output directory.
A minimal javac-only reproduction uses a processor containing the call above:
javac -proc:only -s /tmp/generated-sources \
-processorpath processor.jar \
-processor ExampleProcessor \
path/to/Sample.java
Without -d, javac creates Sample.json beside Sample.java.
Adding a class-output directory:
javac -proc:only \
-s /tmp/generated-sources \
-d /tmp/class-output \
-processorpath processor.jar \
-processor ExampleProcessor \
path/to/Sample.java
creates the intended resource at:
/tmp/class-output/META-INF/example/config.json
The issue appears to have been introduced when annotation processing was enabled in JavacParser by commit a0a25d6. Current J2CL still configures SOURCE_OUTPUT without configuring CLASS_OUTPUT.
Expected behavior
All files created by annotation processors should remain under action-local output directories. Processing must not write beside source inputs.
Local workaround
The local patch points CLASS_OUTPUT at J2CL’s existing action-local generated-source directory:
diff --git a/transpiler/java/com/google/j2cl/transpiler/frontend/javac/JavacParser.java b/transpiler/java/com/google/j2cl/transpiler/frontend/javac/JavacParser.java
--- a/transpiler/java/com/google/j2cl/transpiler/frontend/javac/JavacParser.java
+++ b/transpiler/java/com/google/j2cl/transpiler/frontend/javac/JavacParser.java
@@ -218,6 +218,8 @@
fileManager.setLocationFromPaths(StandardLocation.CLASS_PATH, classPath);
if (sourceGenPath != null) {
fileManager.setLocationFromPaths(
+ StandardLocation.CLASS_OUTPUT, ImmutableList.of(sourceGenPath));
+ fileManager.setLocationFromPaths(
StandardLocation.SOURCE_OUTPUT, ImmutableList.of(sourceGenPath));
}
This was validated with a cache-disabled J2CL action. The processor resource was written beneath _sourcegen/META-INF/..., and no file was created beside the source input.
A separate action-local class-output directory would also address the issue if keeping generated sources and class resources separate is preferred.
J2CL’s javac frontend configures
SOURCE_OUTPUTwhen annotation processing is enabled, but does not configureCLASS_OUTPUT.This affects annotation processors that use the standard API to create a class-output resource with an originating element:
On JDK 18 and later, javac propagates the originating element’s source file to the
JavaFileManageras an originating file. WhenCLASS_OUTPUThas not been configured, javac may use that source file as the sibling placement hint.Observed with JDK 21.0.9:
SOURCE_OUTPUTconfigured, the resource is written beside the originating source input.CLASS_OUTPUTcauses the complete resource path to be written beneath that output directory.A minimal javac-only reproduction uses a processor containing the call above:
Without
-d, javac createsSample.jsonbesideSample.java.Adding a class-output directory:
creates the intended resource at:
The issue appears to have been introduced when annotation processing was enabled in
JavacParserby commit a0a25d6. Current J2CL still configuresSOURCE_OUTPUTwithout configuringCLASS_OUTPUT.Expected behavior
All files created by annotation processors should remain under action-local output directories. Processing must not write beside source inputs.
Local workaround
The local patch points
CLASS_OUTPUTat J2CL’s existing action-local generated-source directory:This was validated with a cache-disabled J2CL action. The processor resource was written beneath
_sourcegen/META-INF/..., and no file was created beside the source input.A separate action-local class-output directory would also address the issue if keeping generated sources and class resources separate is preferred.