MethodHandles.Lookup.defineResource?

Peter Levart peter.levart at gmail.com
Wed Aug 29 16:20:43 UTC 2018


Hi Stephen,

On 08/28/2018 11:21 PM, Stephen Colebourne wrote:
>> So is there a way to achieve what you want for your test with existing API?
> Probably. I could have a separate maven module creating a separate
> modular jar file with the testing resource in it, and run the test
> using both the classpath mode and modulepath. I'm not going to be
> doing that as the benefits are too low compared to the cost.

The cost is not that big if you for example create yourself a reusable 
utility. You don't need to create maven modules etc., just to have a 
named or unnamed module participating in your test.

Say you have the following library class you want to test (this should 
be equivalent to your ExampleMarketDataBuilder):

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public class ResUtil {

     public static String readResource(ClassLoader classLoader, String 
resName) {
         URL url = classLoader.getResource(resName);
         return url == null ? null : readUrl(url);
     }

     public static String readResource(Class<?> clazz, String resName) {
         URL url = clazz.getResource(resName);
         return url == null ? null : readUrl(url);
     }

     private static String readUrl(URL url) {
         try (InputStream in = url.openStream()) {
             byte[] bytes = in.readAllBytes();
             return new String(bytes, StandardCharsets.UTF_8);
         } catch (IOException e) {
             throw new UncheckedIOException(e);
         }
     }
}


You can test it in both modes with the following test:

import lib.ResUtil;
import si.pele.layerbuilder.ModuleLayerBuilder;
import java.net.URLClassLoader;

public class ResTest {
     public static void main(String[] args) throws Exception {

         ModuleLayerBuilder builder = new ModuleLayerBuilder();
         builder
             .module("my.mod", mb -> mb
                 .resource(
                     "module-info.java",
                     "module my.mod {",
                     "  opens my.pkg;",
                     "}"
                 )
                 .resource(
                     "my/pkg/Test.java",
                     "package my.pkg;",
                     "public class Test {",
                     "}"
                 )
                 .resource(
                     "my/pkg/readme.txt",
                     "HELLO WORLD!"
                 )
             );

         // test using "--class-path"

         try (URLClassLoader loader = builder.buildClassLoader()) {
             Class<?> testClass = Class.forName("my.pkg.Test", false, 
loader);
             System.out.println("Resolving in --class-path artifact via 
ClassLoader gives: " + ResUtil.readResource(loader, "my/pkg/readme.txt"));
             System.out.println("Resolving in --class-path artifact via 
Class gives: " + ResUtil.readResource(testClass, "readme.txt"));
         }

         // test using "--module-path"

         {
             ModuleLayer layer = builder.buildModuleLayer();
             Module myMod = layer.findModule("my.mod").orElseThrow(() -> 
new RuntimeException("Can't find module: my.mod"));
             ClassLoader loader = myMod.getClassLoader();
             Class<?> testClass = Class.forName("my.pkg.Test", false, 
loader);
             System.out.println("Resolving in --module-path artifact via 
ClassLoader gives: " + ResUtil.readResource(loader, "my/pkg/readme.txt"));
             System.out.println("Resolving in --module-path artifact via 
Class gives: " + ResUtil.readResource(testClass, "readme.txt"));
         }
     }
}


A ModuleLayerBuilder utility is not that complicated given all the 
API(s) that are available in JDK 9+. Here it is (you can adapt it to 
your needs if you want):

http://cr.openjdk.java.net/~plevart/misc/ModuleLayerBuilder/ModuleLayerBuilder.java


Regards, Peter



More information about the core-libs-dev mailing list