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

Reply via email to