将自定义文件夹添加到 bazel java 测试中的类路径

2024-04-25

我正在尝试将大型代码库从 Maven 迁移到 bazel,我发现一些测试写入target/classes and target/test-classes并且生产代码将其读取为类路径上的资源。这是因为 maven Surefire/failsafe 默认从模块目录运行并添加target/classes and target/test-classes到类路径。 对于我来说,要迁移这个大型代码库,唯一合理的解决方案是创建 target、target/classes 和 target/test-classes 文件夹,并将最后两个添加到测试的类路径中。
关于如何实现这一目标有什么想法吗?

Thanks


另一种方法。创建自定义 javaagent 和自定义类加载器,而不是生成测试套件。使用jvm_flags来设置和配置它。

javaagent 有一个 premain 方法。这听起来像是一个自然的地方,可以在常规 main 方法之前执行一些操作,即使它们与类检测、调试、覆盖范围收集或 javaagent 的任何其他常用用途没有任何关系。

自定义javaagent读取系统属性extra.dirs并创建那里指定的目录。然后它读取属性extra.link.path并创建那里指定的符号链接,这样我就可以将资源放置在测试期望的位置,而不必复制它们。

需要类加载器,以便我们可以在运行时修改类路径而无需黑客攻击。最大的优点是该解决方案适用于 Java 10。

自定义类加载器读取系统属性extra.class.path并且(实际上)将其放在前面java.class.path.

以这种方式做事意味着可以使用标准 bazel 规则。

BUILD

runtime_classgen_dirs = ":".join([
            "target/classes",
            "target/test-classes",
])
java_test(
    ...,
    jvm_flags = [
        # agent
        "-javaagent:$(location //tools:test-agent_deploy.jar)",
        "-Dextra.dirs=" + runtime_classgen_dirs,
        # classloader
        "-Djava.system.class.loader=ResourceJavaAgent",
        "-Dextra.class.path=" + runtime_classgen_dirs,
    ],
    ,,,,
    deps = [
        # not runtime_deps, cause https://github.com/bazelbuild/bazel/issues/1566
        "//tools:test-agent_deploy.jartest-agent_deploy.jar"
    ],
    ...,
)

工具/构建

java_binary(
    name = "test-agent",
    testonly = True,
    srcs = ["ResourceJavaAgent.java"],
    deploy_manifest_lines = ["Premain-Class: ResourceJavaAgent"],
    main_class = "ResourceJavaAgent",
    visibility = ["//visibility:public"],
)

工具/资源 JavaAgent.java

import java.io.File;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

// https://stackoverflow.com/questions/60764/how-should-i-load-jars-dynamically-at-runtime
public class ResourceJavaAgent extends URLClassLoader {
    private final ClassLoader parent;

    public ResourceJavaAgent(ClassLoader parent) throws MalformedURLException {
        super(buildClassPath(), null);
        this.parent = parent; // I need the parent as backup for SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        System.out.println("initializing url classloader");
    }

    private static URL[] buildClassPath() throws MalformedURLException {
        final String JAVA_CLASS_PATH = "java.class.path";
        final String EXTRA_CLASS_PATH = "extra.class.path";
        List<String> paths = new LinkedList<>();
        paths.addAll(Arrays.asList(System.getProperty(EXTRA_CLASS_PATH, "").split(File.pathSeparator)));
        paths.addAll(Arrays.asList(System.getProperty(JAVA_CLASS_PATH, "").split(File.pathSeparator)));
        URL[] urls = new URL[paths.size()];
        for (int i = 0; i < paths.size(); i++) {
            urls[i] = Paths.get(paths.get(i)).toUri().toURL(); // important only for resource url, really: this url must be absolute, to pass getClass().getResource("/users.properties").toURI()) with uri that isOpaque == false.
//            System.out.println(urls[i]);
        }
        // this is for spawnVM functionality in tests
        System.setProperty(JAVA_CLASS_PATH, System.getProperty(EXTRA_CLASS_PATH, "") + File.pathSeparator + System.getProperty(JAVA_CLASS_PATH));
        return urls;
    }

    @Override
    public Class<?> loadClass(String s) throws ClassNotFoundException {
        try {
            return super.loadClass(s);
        } catch (ClassNotFoundException e) {
            return parent.loadClass(s);  // we search parent second, not first, as the default URLClassLoader would
        }
    }

    private static void createRequestedDirs() {
        for (String path : System.getProperty("extra.dirs", "").split(File.pathSeparator)) {
            new File(path).mkdirs();
        }
    }

    private static void createRequestedLinks() {
        String linkPaths = System.getProperty("extra.link.path", null);
        if (linkPaths == null) {
            return;
        }
        for (String linkPath : linkPaths.split(",")) {
            String[] fromTo = linkPath.split(":");
            Path from = Paths.get(fromTo[0]);
            Path to = Paths.get(fromTo[1]);
            try {
                Files.createSymbolicLink(from.toAbsolutePath(), to.toAbsolutePath());
            } catch (IOException e) {
                throw new IllegalArgumentException("Unable to create link " + linkPath, e);
            }
        }
    }

    public static void premain(String args, Instrumentation instrumentation) throws Exception {
        createRequestedDirs();
        createRequestedLinks();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将自定义文件夹添加到 bazel java 测试中的类路径 的相关文章

  • 透明平开窗

    我有一点JWindow上面有一个标志 用户可以将东西拖到上面 我主要在 OS X 上开发我的应用程序 为了获得我使用的透明窗口 setBackground new Color 0 0 0 0 在 Mac 上 这工作得很好 但在 Window
  • maven 编译失败,因为我有一个非 maven jar

    我有几个内部库 我还没有 不知道如何添加到我的本地 Maven 存储库中 我已将它们添加到项目的类路径中 但我的 maven compile 失败 指出它无法在外部 jar 中找到类 如预期 ERROR Failed to execute
  • 使用 Spring Data REST 处理自定义异常 (i18n)

    我正在使用 Spring Boot 1 5 4 和 Spring JPA Spring Data REST HATEOAS 我正在寻找一种最佳实践 Spring 方式 来自定义异常 Spring Data REST 正在管理添加 i18n
  • 使用除 SINGLE_TABLE 之外的任何其他 Hibernate 继承策略时 JVM 崩溃

    好吧 这可能不太可能 但还是这样吧 在Java JRE 1 6 0 26 b03 中我有两个类 SuperControl及其子类SubControl 它们都需要是持久对象 我正在使用 Hibernate Annotations 来实现这一点
  • RSA SignatureException:签名长度不正确

    我在签署 rsa 签名时遇到问题 我有一个用私钥加密的签名 然而 当我尝试使用公钥验证它时遇到问题 我得到以下异常 java security SignatureException Signature length not correct
  • 正确使用 JDBC 连接池 (Glassfish)

    我需要在 Java Web 服务中作为会话 bean 实现数据库连接 但我不确定我这样做是否正确 我创建了一个类 public final class SQLUtils private static DataSource m ds null
  • 以编程方式设置 Logback Appender 路径

    我正在尝试以编程方式设置 Logback 附加程序路径 滚动文件附加器 http logback qos ch apidocs ch qos logback core rolling RollingFileAppender html准确地说
  • BlackBerry SQLite:将一个 SQLite 数据库连接到另一个

    我正在尝试使用 SQLite 将一个 SQLite 数据库附加到 BlackBerry 上的另一个数据库附加数据库 http www sqlite org lang attach html命令 Database d1 d2 Statemen
  • C# 中的协变和逆变

    首先我要说的是 我是一名正在学习 C 编程的 Java 开发人员 因此 我会将我所知道的与我正在学习的进行比较 我已经使用 C 泛型几个小时了 我已经能够在 C 中重现我在 Java 中知道的相同内容 除了几个使用协变和逆变的示例 我正在读
  • 打印 jasper 文件时执行报表 SQL 语句时出错

    我修改了一个旧项目 但无法确定这段代码有什么问题 使用下面的 jrxml它创造 jasper文件 当我打印 jasper 文件时 使用此代码JasperPrint jasperPrint JasperFillManager fillRepo
  • Java元数据读写

    是否可以以通用方式 对于所有图像类型 在 Java 中读取和写入元数据 我找到了一些示例 但它们总是特定的 例如 JPEG 或 PNG 我需要一些足够通用的东西 而不是到处都有 if else 语句 我不想重写源代码 但这是一个很好的例子
  • 不要模拟值对象:过于通用的规则,没有解释

    以下是 Mockito 单元测试框架的引用 不要模拟值对象 为什么有人会想要这样做呢 因为实例化对象太痛苦了 gt 无效 原因 如果创造新的装置太困难 那就是一个迹象 代码可能需要一些认真的重构 另一种方法是创建 价值对象的构建者 有一些工
  • 抽象类或接口。哪种方式是正确的?

    有两种方法可以选择抽象类或接口 微软解决方案和Oracle解决方案 微软 设计指南 请使用抽象 在 Visual Basic 中为 MustInherit 类而不是接口来将协定与实现分离 http msdn microsoft com en
  • 在Java中多次读取System.in会导致IOException?

    我正在尝试创建一个小命令行游戏来强化我在过去几个月中在 Java 中学到的一些东西 我正在尝试创建一个名为 readInput 的方法 它返回一个我可以一次又一次调用的字符串 第一次它工作正常 但第二次它会导致 IO Exception 如
  • 战争库中的罐子爆炸

    我们可以将分解的 jar 文件放入 war web inf 库中吗 它在 JBOSS 4 2 中对我不起作用 我收到以下错误并且无法部署应用程序 Caused by javax management RuntimeOperationsExc
  • scala中的协变类型参数需要在java接口中保持不变

    我有一个看起来像这样的特征 一些进一步的信息可以在我自己提出了这个相关问题 https stackoverflow com questions 3695990 inheritance and automatic type conversio
  • Bazel:输出目录的genrule

    我刚刚开始与 Bazel 合作 所以 我提前道歉 我没能弄清楚这一点 我正在尝试运行一个命令 将一堆文件输出到一个目录 并使该目录可用于后续目标 我有两种不同的尝试 使用正则 写我自己的规则 我天真地希望能用一个来做到这一点genrule
  • Google Cloud Messaging - 立即收到或长时间延迟收到的消息

    我在大学最后一年的项目中使用谷歌云消息传递 一切正常 但我在使用 GCM 时遇到了一些麻烦 通常 消息要么几乎立即传递 要么有很大的延迟 我读过这篇文章 但我真的认为它不适用于这种情况 GCM 通常会在消息发送后立即传送消息 然而 这并不总
  • 如果抛出RuntimeException,是否可以将其作为异常捕获?

    如果我有一个try抛出一个块RuntimException子类 可以是后续的catch块将其捕获为Exception 具体来说 public class MyAppException extends RuntimeException In
  • 如何在java 1.8中从org.jboss.jca.adapters.jdbc.jdk8.WrappedConnectionJDK8转换为oracle.jdbc.OracleConnection

    如何在 java 1 8 中从 org jboss jca adapters jdbc jdk8 WrappedConnectionJDK8 转换为 oracle jdbc OracleConnection 目前我正在这样使用并得到以下异常

随机推荐