8332226: "Invalid package name:" from source launcher

Reviewed-by: alanb
This commit is contained in:
Christian Stein 2024-05-24 12:24:15 +00:00
parent 5a2ba952b1
commit f16265d69b
2 changed files with 67 additions and 20 deletions
src/jdk.compiler/share/classes/com/sun/tools/javac/launcher
test/langtools/tools/javac/launcher

@ -32,6 +32,7 @@ import com.sun.tools.javac.resources.LauncherProperties.Errors;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.module.InvalidModuleDescriptorException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
@ -39,6 +40,10 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.lang.model.SourceVersion;
/**
* Describes a launch-able Java compilation unit.
@ -113,25 +118,62 @@ public record ProgramDescriptor(
}
public Set<String> computePackageNames() {
try (var stream = Files.find(sourceRootPath, 99, (path, attr) -> attr.isDirectory())) {
var names = new TreeSet<String>();
stream.filter(ProgramDescriptor::containsAtLeastOneRegularFile)
.map(sourceRootPath::relativize)
.map(Path::toString)
.filter(string -> !string.isEmpty())
.map(string -> string.replace(File.separatorChar, '.'))
.forEach(names::add);
return names;
} catch (IOException exception) {
throw new UncheckedIOException(exception);
return explodedPackages(sourceRootPath);
}
// -- exploded directories --> based on jdk.internal.module.ModulePath
private static Set<String> explodedPackages(Path dir) {
String separator = dir.getFileSystem().getSeparator();
try (Stream<Path> stream = Files.find(dir, Integer.MAX_VALUE,
(path, attrs) -> attrs.isRegularFile() && !isHidden(path))) {
return stream.map(dir::relativize)
.map(path -> toPackageName(path, separator))
.flatMap(Optional::stream)
.collect(Collectors.toSet());
} catch (IOException x) {
throw new UncheckedIOException(x);
}
}
private static boolean containsAtLeastOneRegularFile(Path directory) {
try (var stream = Files.newDirectoryStream(directory, Files::isRegularFile)) {
return stream.iterator().hasNext();
} catch (IOException exception) {
throw new UncheckedIOException(exception);
/**
* Maps the relative path of an entry in an exploded module to a package
* name.
*
* @throws InvalidModuleDescriptorException if the name is a class file in
* the top-level directory (and it's not module-info.class)
*/
private static Optional<String> toPackageName(Path file, String separator) {
assert file.getRoot() == null;
Path parent = file.getParent();
if (parent == null) {
String name = file.toString();
if (name.endsWith(".class") && !name.equals("module-info.class")) {
String msg = name + " found in top-level directory"
+ " (unnamed package not allowed in module)";
throw new InvalidModuleDescriptorException(msg);
}
return Optional.empty();
}
String pn = parent.toString().replace(separator, ".");
if (SourceVersion.isName(pn)) {
return Optional.of(pn);
} else {
// not a valid package name
return Optional.empty();
}
}
/**
* Returns true if the given file exists and is a hidden file
*/
private static boolean isHidden(Path file) {
try {
return Files.isHidden(file);
} catch (IOException ioe) {
return false;
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 8304400
* @bug 8304400 8332226
* @summary Test source launcher running Java programs contained in one module
* @modules jdk.compiler/com.sun.tools.javac.launcher
* @run junit ModuleSourceLauncherTests
@ -112,6 +112,8 @@ class ModuleSourceLauncherTests {
Files.writeString(barFolder.resolve("Bar.java"), "package bar; public record Bar() {}");
var bazFolder = Files.createDirectories(base.resolve("baz"));
Files.writeString(bazFolder.resolve("baz.txt"), "baz");
var badFolder = Files.createDirectories(base.resolve(".bad"));
Files.writeString(badFolder.resolve("bad.txt"), "bad");
Files.writeString(base.resolve("module-info.java"),
"""
@ -140,8 +142,11 @@ class ModuleSourceLauncherTests {
assertEquals("m", module.getName());
var reference = module.getLayer().configuration().findModule(module.getName()).orElseThrow().reference();
try (var reader = reference.open()) {
var actual = reader.list().toList();
assertLinesMatch(
"""
.bad/
.bad/bad.txt
bar/
bar/Bar.class
bar/Bar.java
@ -152,8 +157,8 @@ class ModuleSourceLauncherTests {
foo/Main.java
module-info.class
module-info.java
""".lines(),
reader.list());
""".lines().toList(),
actual, "Actual lines -> " + actual);
}
}