以编程方式检测JRE中的“--preview”模式

8
自Java 11起,Java编译器和运行时环境可以启用预览模式。这使得可以预览新的功能。 (JEP 12)
java --enable-preview

我该如何在Java内部检测JVM是否已启用预览模式?

我的目的是在应用程序状态页面/JSON中描述正在运行的容器,以便进行devops概述。

到目前为止,我已经查看了系统属性和标志,但都没有任何提示。


2
尝试使用你需要的功能显式地运行代码,并处理如果JVM出现问题的情况。 - Thorbjørn Ravn Andersen
2
只是好奇,你为什么想这样做?因为这样的代码只能在设置了标志的情况下编译,否则它甚至无法编译,更别提执行了。 - Naman
也许这个答案可以解决你的问题,可以直接使用或者作为一个起点。我自己没有实践过,但看起来类似于你所询问的内容。 - Kaan
2
@naman,你可以将大多数Java 11代码编译,然后将其余部分编译为预览版本支持的任何内容。如果该代码在try块中加载,则可以处理失败。 - Thorbjørn Ravn Andersen
2
@kaan,这明确要求热点功能,使代码依赖于供应商。 - Thorbjørn Ravn Andersen
1个回答

4

您可以检查Java类文件的minor_version。如果值为0xFFFF则说明该类文件是使用 --enable-preview 编译的。详见https://stackoverflow.com/a/58821511/868941

以下是一个简单的程序用于检查此内容(请注意,这是启用预览功能的Java 13代码!)。

public final class ClassFileVersion {

    private final int major;
    private final int minor;

    private ClassFileVersion(int major, int minor) {
        this.major = major;
        this.minor = minor;
    }

    public static ClassFileVersion of(Class<?> classFile) throws IOException {
        try (InputStream is = classFile.getResourceAsStream("/%s.class".formatted(classFile.getName().replace('.', '/')))) {
            var buffer = new byte[8];
            if (is.read(buffer) != buffer.length) {
                throw new AssertionError("Not a Java Class File!");
            }
            return new ClassFileVersion(readUnsignedShort(buffer, 6), readUnsignedShort(buffer, 4));
        }
    }

    public String getVersionNumber() {
        return "%d.%d".formatted(major, minor);
    }

    public boolean isEnablePreview() {
        return major >= 55 && minor == 0xFFFF;
    }

    @Override
    public String toString() {
        return (major < 49 ? "JDK " : "Java SE ") +
            switch(major) {
                case 45 -> "1.1";
                case 46 -> "1.2";
                case 47 -> "1.3";
                case 48 -> "1.4";
                case 49 -> "5";
                case 50 -> "6";
                case 51 -> "7";
                case 52 -> "8";
                case 53 -> "9";
                case 54 -> "10";
                case 55 -> "11";
                case 56 -> "12";
                case 57 -> "13";
                case 58 -> "14";
                default -> throw wrongVersion();
            } +
            switch(minor) {
                case 0 -> "";
                case 3 -> {
                    if (major != 45) {
                        throw wrongVersion();
                    }
                    yield "";
                }
                case 0xFFFF -> " --enable-preview";
                default -> throw wrongVersion();
            };
    }

    private static int readUnsignedShort(byte[] buffer, int offset) {
        return ((buffer[offset] & 0xff) << 8) + (buffer[++offset] & 0xff);
    }

    private AssertionError wrongVersion() {
        return new AssertionError("Wrong Java Class File Version: %d.%d".formatted(major, minor));
    }
    // to run this code (JDK 13 needed):
    // java --enable-preview --source 13 ClassFileVersion.java 
    public static void main(String[] args) throws IOException {
        // prints "Java SE 13 --enable-preview"
        System.out.println(ClassFileVersion.of(ClassFileVersion.class));
    }

}

1
这个测试是用来检查类文件是否已经使用了 --enable-preview 编译,而不是在运行时启用了预览。显然,如果结果为 true,那么它必须是有效的,但是当类文件没有使用预览编译,但在运行时启用了预览时,结果将是错误的。 - Holger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接