gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 06:45:47 25 4
gpt4 key购买 nike

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

谢谢

最佳答案

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

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

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

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

自定义类加载器读取系统属性 extra.class.path 并(实际上)将其添加到 java.class.path 中的内容之前。

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

构建

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"],
)

工具/ResourceJavaAgent.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();
}
}

关于java - 将自定义文件夹添加到 bazel java 测试中的类路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43709701/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com