jhipster / jhipster/prettier-java
Parse fails on a raw NUL (U+0000) in a string literal since 2.9.0
- Dominant language
- Java
- Stars
- 1.2k
- Forks
- 120
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 27
Description
### Summary
A raw NUL (`U+0000`) inside a string literal is legal Java, but `prettier-plugin-java` 2.9.0 onwards fails to parse a file containing one. 2.8.1 and earlier parse it fine.
This is the same family as #1046 — the web-tree-sitter grammar being stricter than the JLS — but a different rule: that one was identifiers, this is string literal contents, so #1058 does not cover it.
### Reproduction
The literal cannot be pasted into an issue body, so create it with:
```bash
python3 -c "open('A.java','wb').write(b'class A {\n String s = \"foo' + bytes([0]) + b'bar\";\n}\n')"
npx prettier --plugin=prettier-plugin-java --write A.java
```
### Actual
```
[error] A.java: Error: Failed to parse: ... (string_literal (string_fragment) (ERROR (UNEXPECTED ...)))
```
`prettier --write` exits 2 and leaves the file untouched.
### Expected
The file formats, as it does on 2.8.1 and earlier.
### Why this is valid Java
JLS 3.10.5 defines a `StringCharacter` as any `InputCharacter` except `"` and `\`, where `InputCharacter` excludes only CR and LF. `U+0000` is therefore permitted, and `javac` compiles the file without complaint. We have a test file carrying one that has compiled and passed in CI for four months.
### Bisection
Holding `prettier` at 3.4.2 so the plugin is the only variable, against the same real-world file:
| prettier-plugin-java | result |
| --- | --- |
| 2.6.7 | parses OK |
| 2.7.4 | parses OK |
| 2.8.0 | parses OK |
| 2.8.1 | parses OK |
| 2.9.7 | **Failed to parse** |
| 2.10.0 | **Failed to parse** |
| 2.10.3 | **Failed to parse** |
Consistent with the parser switch in 2.9.
### Impact
The failure is a hard stop rather than a formatting difference: prettier cannot format what it cannot parse, so `--write` cannot repair it and `--check` fails the commit. For anyone running prettier from a pre-commit hook, upgrading past 2.8.1 blocks commits on any file containing such a literal, pointing at a byte that is invisible in an editor and in a diff.
The workaround on our side is to write the escape `\0` instead of the raw byte, which is better style regardless — noting that the six-character unicode escape for zero is not a substitute, since Java resolves unicode escapes before lexing and so reintroduces the raw NUL into the token stream.
This is presumably a `tree-sitter-java-orchard` issue rather than prettier-java's own code, but filing here as #1046 was, since this is where the regression surfaces.
Contributor guide
Research direction
Start by reproducing the failure with the provided Python command and npx prettier invocation on A.java, then compare behavior with 2.8.1. Trace the parser switch introduced in 2.9 and inspect the tree-sitter-java-orchard path, alongside related issue #1046. Done means files containing a raw NUL in a string literal format successfully and the existing test file carrying one still passes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- compilers, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100