@@ -56,6 +56,7 @@ public class Jar implements SecureJar {
5656 private final JarModuleDataProvider moduleDataProvider ;
5757 private final Set <String > packages ;
5858 private final List <Provider > providers ;
59+ private final URI filesystemRootUri ;
5960
6061 @ Override
6162 public ModuleDataProvider moduleDataProvider () {
@@ -85,6 +86,7 @@ public Jar(Supplier<Manifest> defaultManifest, Function<SecureJar, JarMetadata>
8586 this .moduleDataProvider = new JarModuleDataProvider (this );
8687
8788 this .filesystemRoot = newFileSystem (pathfilter , validPaths );
89+ this .filesystemRootUri = fixUri (this .filesystemRoot );
8890 this .filesystemPrimary = validPaths [validPaths .length - 1 ];
8991 this .manifest = findManifest (validPaths , defaultManifest );
9092 this .nameOverrides = gatherVersionedFiles ();
@@ -264,7 +266,7 @@ public Manifest getManifest() {
264266 }
265267
266268 public URI getURI () {
267- return this .filesystemRoot . toUri () ;
269+ return this .filesystemRootUri ;
268270 }
269271
270272 public ModuleDescriptor computeDescriptor () {
@@ -410,6 +412,51 @@ private Manifest findManifest(Path[] paths, Supplier<Manifest> defaultManifest)
410412 }
411413 }
412414
415+ // ZipPath has an issue where it decodes the URI to prevent double encoding, but then
416+ // uses a constructor of URI that doesn't encode brackets.
417+ // This causes an invalid URI when doing the Path.of(zipPath.toUri()).
418+ // So lets see if there are []s and then encode them.
419+ private static URI fixUri (Path path ) {
420+ var uri = path .toUri ();
421+ // If we're not jar (ZipPath) then trust it isn't broken
422+ // this could come back to bite me, but I don't want to go down the road later.
423+ if (!"jar" .equals (uri .getScheme ()))
424+ return uri ;
425+
426+ var ssp = uri .getRawSchemeSpecificPart ();
427+ var hasBrackets = ssp .indexOf ('[' ) != -1 || ssp .indexOf (']' ) != -1 ;
428+ if (!hasBrackets )
429+ return uri ;
430+
431+ int len = uri .getScheme ().length () + 1 ;
432+ len += ssp .length () + 2 ; // At least one bracket, so 2 extra
433+ if (uri .getRawFragment () != null )
434+ len += uri .getRawFragment ().length () + 1 ;
435+
436+ var buf = new StringBuilder (len );
437+ buf .append (uri .getScheme ()).append (':' );
438+
439+ for (int x = 0 ; x < ssp .length (); x ++) {
440+ var c = ssp .charAt (x );
441+ if (c == '[' )
442+ buf .append ("%5B" );
443+ else if (c == ']' )
444+ buf .append ("%5D" );
445+ else
446+ buf .append (c );
447+ }
448+
449+ if (uri .getRawFragment () != null )
450+ buf .append ('#' ).append (uri .getRawFragment ());
451+
452+ try {
453+ // we have to use the full string because all other constructors try to do escaping, but don't escape [] correctly.
454+ return new URI (buf .toString ());
455+ } catch (Exception ex ) {
456+ throw new AssertionError (ex );
457+ }
458+ }
459+
413460 private record JarModuleDataProvider (Jar jar ) implements ModuleDataProvider {
414461 @ Override
415462 public String name () {
0 commit comments