Skip to content

Encode location names in InMemoryJavaFileManager file URIs - #554

Draft
rootkiller6788 wants to merge 2 commits into
google:mainfrom
rootkiller6788:fix-inmemory-filemanager-module-uri
Draft

Encode location names in InMemoryJavaFileManager file URIs#554
rootkiller6788 wants to merge 2 commits into
google:mainfrom
rootkiller6788:fix-inmemory-filemanager-module-uri

Conversation

@rootkiller6788

Copy link
Copy Markdown

Problem

When a compilation involves a module, javac calls StandardJavaFileManager.getLocationForModule(CLASS_OUTPUT, name), which returns a Location whose name is CLASS_OUTPUT[name] (e.g. CLASS_OUTPUT[foo]).

InMemoryJavaFileManager.uriForJavaFileObject() and uriForFileObject() build an in-memory URI directly from location.getName():

"mem:///" + location.getName() + '/' + ...

Since [ and ] are illegal characters in a URI path, URI.create("mem:///CLASS_OUTPUT[foo]/...") throws:

java.lang.IllegalArgumentException: Illegal character in path at index 19: mem:///CLASS_OUTPUT[foo]/...

This makes it impossible to use compile-testing when the compiler resolves a module output location. (Reported in #335.)

Fix

Percent-encode the brackets in the location name before building the URI, via a new private locationName(Location) helper. Standard (non-module) location names such as SOURCE_OUTPUT or CLASS_OUTPUT contain no brackets, so they are unaffected.

Tests

Added InMemoryJavaFileManagerTest with two tests (getJavaFileForOutput and getFileForOutput) that exercise a location named CLASS_OUTPUT[foo]. Both throw the IllegalArgumentException before this change and pass after it.

Fixes #335.

Module locations returned by StandardJavaFileManager.getLocationForModule have names such as CLASS_OUTPUT[foo]. The brackets are illegal in a URI path, so URI.create("mem:///CLASS_OUTPUT[foo]/...") throws IllegalArgumentException.

Percent-encode the brackets before building in-memory file URIs.

Fixes google#335.
@cgdecker

Copy link
Copy Markdown
Member

Given this comment on #335, it sounds like we shouldn't bother with this since Compile Testing support for modules is nonexistent even if we fixed this.

If we were to fix this, though, I don't think this is quite the right approach either. We could avoid manual escaping by using the URI constructor that takes 4 parameters, like new URI("mem", null, path, null).

@cgdecker cgdecker added the P3 label Aug 21, 2026
Per review feedback, URI.create() combined with manual percent-encoding is
brittle. Build the path from the raw location name and let the
URI(scheme, authority, path, fragment) constructor percent-encode any
characters that are illegal in a URI path. An empty (rather than null)
authority keeps the resulting mem:///... URIs in the same form as before.

Also strengthen InMemoryJavaFileManagerTest to assert the encoded URI path
and cover getJavaFileForInput(), the path javac's module validation hits.
@rootkiller6788

Copy link
Copy Markdown
Author

Thank you for the review, and for pointing me to the earlier discussion on #335 — I read it before revising.

On whether this is worth doing at all: I've kept the change deliberately minimal. It doesn't attempt to add module support; it only stops InMemoryJavaFileManager from throwing IllegalArgumentException when it is handed a Location whose name happens to contain brackets. javac can reach that path on its own during module validation (it calls getJavaFileForInput() on the module's CLASS_OUTPUT location), so the crash is arguably a latent robustness bug rather than an end-to-end module feature. If you'd still rather defer this until proper module support is designed, I'm happy to close the PR — just let me know.

On the approach: agreed, the manual percent-encoding was the wrong call. I've replaced it with the multi-argument URI constructor, building the path from the raw location name and letting the constructor quote any illegal characters:

private static URI memUri(String path) {
  try {
    return new URI("mem", "", path, null);
  } catch (URISyntaxException impossible) {
    throw new AssertionError(impossible);
  }
}

One deliberate detail: I pass an empty authority ("") rather than null, so the resulting URIs keep the previous mem:///... form for ordinary (non-module) locations — with null they would become mem:/..., which would be an unrelated behavioral change. Since the constructor quotes illegal characters rather than rejecting them, the URISyntaxException cannot actually occur for the paths built here, so it is wrapped in an AssertionError, matching the repo's existing convention.

The tests now assert the encoded URI (getRawPath() ends up .../CLASS_OUTPUT%5Bfoo%5D/...), keep a standard-location case to lock in the unchanged URI form, and add coverage for getJavaFileForInput, which is the path javac's module validation actually hits.

Could you please take another look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] InMemoryJavaFileManager.uriForJavaFileObject() breaks when supplied with a Locations.ModuleLocationHandler

2 participants