Add posibility to add custom ModuleReaderFactory to ModuleFinder

Alan Bateman Alan.Bateman at oracle.com
Fri Sep 28 12:03:46 UTC 2018


On 28/09/2018 10:01, Alex Sviridov wrote:
>  From java 9 we can create JPMS layers and dynamically add modules to it. At the same time different types of java archives can be JPMS modules - .jar, .war, .ear. However, the problem is that it is possible to add only .jar archives by default. I opened an issue here  https://bugs.openjdk.java.net/browse/JDK-8203330  and as it was found out it is necessary to implement custom ModuleFinder.
>
> Trying to implement ModuleFinder I understood that it is necessary to rewrite (or take from) the "half" of jdk.intenal what is a very bad way.
>
> Lets' consider what I need to add .war arhives to JPMS layer. I need: 1) to understand if I can work with this type of archive or I can not (if .war is supported) 2). to map file location, for example instead of "module-info.java" I must find "WEB-INF/classes/module-info.java" etc. For that I don't need to create ModuleDescriptor, ModuleReference, ModuleFinder.
>
> So I suggest to overload ModuleFinder.of() method adding as a parameter custom ModuleReaderFactory. For example to add ModuleFinder#of(ModuleReaderFactory factory, Path... entries). ModuleReaderFactory must have such method - createModuleReader(Path path). Such solution will also help Jakarta EE developers a lot of.
>
Creating a ModuleFinder that can find modules in WAR files shouldn't 
need any API additions or copying of code from the JDK. Where are the 
pain points that you are running into? Is it because a WAR files is 
single artifact that may contain several modules (the application module 
under WEB-INF/classes and dependences are packaged as JAR files under 
WEB-INF/lib). One thing to be aware of is that the zip file system 
provider was updated recently to improve its support for opening JAR 
files in custom file systems, this means you can do things like this:

         ClassLoader scl = ClassLoader.getSystemClassLoader();
         try (FileSystem warfs = FileSystems.newFileSystem(war, scl)) {
             Path classes = warfs.getPath("/WEB-INF/classes");
             Files.walk(classes)
                     .map(p -> classes.relativize(p))
                     .forEach(System.out::println);

             Path lib = warfs.getPath("WEB-INF/lib");
             Files.find(lib, 1, (path, attrs) -> 
path.toString().endsWith("jar"))
                     .forEach(jar -> {
                         try (FileSystem jarfs = 
FileSystems.newFileSystem(jar, scl)) {
                             Path top = jarfs.getPath("/");
                             Files.walk(top)
                                     .map(p -> top.relativize(p))
                                     .forEach(System.out::println);
                         } catch (IOException ioe) {
                             throw new UncheckedIOException(ioe);
                         }
                     });
         }

Another thing to be aware of is that the ModuleFinder.of(Path[]) can 
also deal with JAR files that are packaged inside other JAR files. It 
does have to extract them to a temporary location on the file system and 
there may several potential improvements that could be just, just hasn't 
been an area to spend time on.

-Alan.





More information about the jigsaw-dev mailing list