Add posibility to add custom ModuleReaderFactory to ModuleFinder
Alan Bateman
Alan.Bateman at oracle.com
Fri Sep 28 13:51:56 UTC 2018
On 28/09/2018 13:10, Alex Sviridov wrote:
> Hi Alan
>
> Thank you for your answer. But my main problem is not jars inside .war
> - this is a so far from my current problem. Now I need to 1) add .war
> file to layer 2). to map file location, for example instead of
> "module-info.java" I must find "WEB-INF/classes/module-info.java" etc.
> That is all I need. How can I do it without implementing ModuleFinder?
You'll need a ModuleFinder because the packaging formats that
ModuleFinder.of(Path) is required to support doesn't know anything about
WAR files. It's not super difficult to develop your own. I attach a
simple implementation that may get you started. It's really basic but
would need a few iterations to be robust. Invoke
WarModuleFinder.of(Path) with the file path to the WAR file and it will
create a ModuleFinder that can find the application module in the WAR
file. A more complete implementation would be a lot more robust and
polished that this sample, it would also find the modules WEB-INF/lib.
Once you have a ModuleFinder then you specify it to Conguration::resolve
method when resolving the application as the root module. You'll
probably start with something like:
Path war = Path.of("app.war");
ModuleFinder finder = WarModuleFinder.of(war);
String appModuleName = finder.findAll().stream()
.findFirst()
.map(ModuleReference::descriptor)
.map(ModuleDescriptor::name)
.orElseThrow();
ModuleLayer boot = ModuleLayer.boot();
Configuration cf = boot.configuration().resolve(finder,
ModuleFinder.of(), Set.of(appModuleName));
ModuleLayer layer = boot.defineModulesWithOneLoader(cf,
ClassLoader.getSystemClassLoader());
and now you have a module layer with the application module loaded from
the WEB-INF/classes part of the WAR file.
-Alan
static class WarModuleFinder implements ModuleFinder {
private final FileSystem warfs;
private final Path classes;
private final ModuleReference mref;
private WarModuleFinder(Path warfile) throws IOException {
ClassLoader scl = ClassLoader.getSystemClassLoader();
FileSystem fs = FileSystems.newFileSystem(warfile, scl);
Path classes = fs.getPath("/WEB-INF/classes");
ModuleDescriptor descriptor;
try (InputStream in =
Files.newInputStream(classes.resolve("module-info.class"))) {
descriptor = ModuleDescriptor.read(in, () ->
packages(classes));
}
this.warfs = fs;
this.classes = classes;
this.mref = new ModuleReference(descriptor, classes.toUri()) {
@Override
public ModuleReader open() {
return new WarModuleReader();
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[module ");
sb.append(descriptor().name());
sb.append(", location=");
sb.append(location());
sb.append("]");
return sb.toString();
}
};
}
static WarModuleFinder of(Path war) throws IOException {
return new WarModuleFinder(war);
}
@Override
public Optional<ModuleReference> find(String name) {
if (name.equals(mref.descriptor().name())) {
return Optional.of(mref);
} else {
return Optional.empty();
}
}
@Override
public Set<ModuleReference> findAll() {
return Set.of(mref);
}
private Set<String> packages(Path classes) {
try {
return Files.find(classes, Integer.MAX_VALUE,
(path, attrs) -> !attrs.isDirectory())
.map(entry -> classes.relativize(entry).toString())
.map(this::toPackageName)
.flatMap(Optional::stream)
.collect(Collectors.toSet());
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
}
private Optional<String> toPackageName(String name) {
int index = name.lastIndexOf("/");
if (index > 0) {
return Optional.of(name.substring(0,
index).replace('/', '.'));
} else {
return Optional.empty();
}
}
class WarModuleReader implements ModuleReader {
private volatile boolean closed;
private void ensureOpen() throws IOException {
if (closed) throw new IOException("ModuleReader is
closed");
}
public Optional<URI> find(String name) throws IOException {
ensureOpen();
if (!name.startsWith("/")) {
Path entry = classes.resolve(name);
if (Files.exists(entry)) {
return Optional.of(entry.toUri());
}
}
return Optional.empty();
}
public Stream<String> list() throws IOException {
ensureOpen();
return Files.walk(classes)
.map(entry -> classes.relativize(entry).toString())
.filter(name -> name.length() > 0);
}
public void close() {
closed = true;
}
}
}
More information about the jigsaw-dev
mailing list