google / google/j2cl

Annotation processors can write `CLASS_OUTPUT` resources beside source inputs

Open Beginner friendly
#298 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
1.4k
Forks
161
PR merge metrics
No merged PRs in 30d

Description

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:

```java
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:

```text
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:

```text
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:

```text
/tmp/class-output/META-INF/example/config.json
```

The issue appears to have been introduced when annotation processing was enabled in `JavacParser` by commit a0a25d692efa2e32b21cba64f90a333e37d25b0d. 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
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.

Contributor guide

Open the contributing guide

Research direction

Start in transpiler/java/com/google/j2cl/transpiler/frontend/javac/JavacParser.java, where SOURCE_OUTPUT and CLASS_PATH are configured, and review the annotation-processing setup. Run the cache-disabled J2CL action described in the issue with a processor resource; done means the resource is written under an action-local output directory and nothing is created beside the source input.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
compilers
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.