From b7b3b65ac66a584c21cc779cbe2263dbfda5d8bb Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Thu, 26 Sep 2024 22:28:52 +0200 Subject: [PATCH] Make class file version more efficient and avoid experimental API on it. --- .../java/net/bytebuddy/ClassFileVersion.java | 179 +++++------------- .../bytebuddy/ClassFileVersionOtherTest.java | 10 + .../net/bytebuddy/ClassFileVersionTest.java | 30 +-- 3 files changed, 70 insertions(+), 149 deletions(-) diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/ClassFileVersion.java b/byte-buddy-dep/src/main/java/net/bytebuddy/ClassFileVersion.java index b72fed9249..bf025ffb9c 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/ClassFileVersion.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/ClassFileVersion.java @@ -20,7 +20,6 @@ import net.bytebuddy.build.HashCodeAndEqualsPlugin; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.ClassFileLocator; -import net.bytebuddy.utility.OpenedClassReader; import net.bytebuddy.utility.nullability.MaybeNull; import org.objectweb.asm.Opcodes; @@ -160,6 +159,33 @@ public class ClassFileVersion implements Comparable, Serializa */ public static final ClassFileVersion JAVA_V23 = new ClassFileVersion(Opcodes.V23); + /** + * An array of class file versions in their sorting order. + */ + private static final ClassFileVersion[] CLASS_FILE_VERSIONS = new ClassFileVersion[] {ClassFileVersion.JAVA_V1, + ClassFileVersion.JAVA_V2, + ClassFileVersion.JAVA_V3, + ClassFileVersion.JAVA_V4, + ClassFileVersion.JAVA_V5, + ClassFileVersion.JAVA_V6, + ClassFileVersion.JAVA_V7, + ClassFileVersion.JAVA_V8, + ClassFileVersion.JAVA_V9, + ClassFileVersion.JAVA_V10, + ClassFileVersion.JAVA_V11, + ClassFileVersion.JAVA_V12, + ClassFileVersion.JAVA_V13, + ClassFileVersion.JAVA_V14, + ClassFileVersion.JAVA_V15, + ClassFileVersion.JAVA_V16, + ClassFileVersion.JAVA_V17, + ClassFileVersion.JAVA_V18, + ClassFileVersion.JAVA_V19, + ClassFileVersion.JAVA_V20, + ClassFileVersion.JAVA_V21, + ClassFileVersion.JAVA_V22, + ClassFileVersion.JAVA_V23}; + /** * A version locator for the executing JVM. */ @@ -212,76 +238,20 @@ public static ClassFileVersion ofMinorMajor(int versionNumber) { * @return The appropriate class file version. */ public static ClassFileVersion ofJavaVersionString(String javaVersionString) { - return ofJavaVersionString(javaVersionString, OpenedClassReader.EXPERIMENTAL); - } - - /** - * Returns the Java class file by its representation by a version string in accordance to the formats known to javac. - * - * @param javaVersionString The Java version string. - * @param experimental {@code true} if unknown version strings should be parsed as if they were known. - * @return The appropriate class file version. - */ - public static ClassFileVersion ofJavaVersionString(String javaVersionString, boolean experimental) { - if (javaVersionString.equals("1.1")) { - return JAVA_V1; - } else if (javaVersionString.equals("1.2")) { - return JAVA_V2; - } else if (javaVersionString.equals("1.3")) { - return JAVA_V3; - } else if (javaVersionString.equals("1.4")) { - return JAVA_V4; - } else if (javaVersionString.equals("1.5") || javaVersionString.equals("5")) { - return JAVA_V5; - } else if (javaVersionString.equals("1.6") || javaVersionString.equals("6")) { - return JAVA_V6; - } else if (javaVersionString.equals("1.7") || javaVersionString.equals("7")) { - return JAVA_V7; - } else if (javaVersionString.equals("1.8") || javaVersionString.equals("8")) { - return JAVA_V8; - } else if (javaVersionString.equals("1.9") || javaVersionString.equals("9")) { - return JAVA_V9; - } else if (javaVersionString.equals("1.10") || javaVersionString.equals("10")) { - return JAVA_V10; - } else if (javaVersionString.equals("1.11") || javaVersionString.equals("11")) { - return JAVA_V11; - } else if (javaVersionString.equals("1.12") || javaVersionString.equals("12")) { - return JAVA_V12; - } else if (javaVersionString.equals("1.13") || javaVersionString.equals("13")) { - return JAVA_V13; - } else if (javaVersionString.equals("1.14") || javaVersionString.equals("14")) { - return JAVA_V14; - } else if (javaVersionString.equals("1.15") || javaVersionString.equals("15")) { - return JAVA_V15; - } else if (javaVersionString.equals("1.16") || javaVersionString.equals("16")) { - return JAVA_V16; - } else if (javaVersionString.equals("1.17") || javaVersionString.equals("17")) { - return JAVA_V17; - } else if (javaVersionString.equals("1.18") || javaVersionString.equals("18")) { - return JAVA_V18; - } else if (javaVersionString.equals("1.19") || javaVersionString.equals("19")) { - return JAVA_V19; - } else if (javaVersionString.equals("1.20") || javaVersionString.equals("20")) { - return JAVA_V20; - } else if (javaVersionString.equals("1.21") || javaVersionString.equals("21")) { - return JAVA_V21; - } else if (javaVersionString.equals("1.22") || javaVersionString.equals("22")) { - return JAVA_V22; - } else if (javaVersionString.equals("1.23") || javaVersionString.equals("23")) { - return JAVA_V23; - } else { - if (experimental) { - try { - int version = Integer.parseInt(javaVersionString.startsWith("1.") - ? javaVersionString.substring(2) - : javaVersionString); - if (version > 0) { - return new ClassFileVersion(BASE_VERSION + version); - } - } catch (NumberFormatException ignored) { + int index = javaVersionString.indexOf('.'); + try { + int javaVersion; + if (index == -1) { + javaVersion = Integer.parseInt(javaVersionString); + } else { + javaVersion = Integer.parseInt(javaVersionString.substring(index + 1)); + if (Integer.parseInt(javaVersionString.substring(0, index)) != 1 || javaVersion > 8) { + throw new IllegalArgumentException("Java versions with minor version must be of format 1.[1-7]: " + javaVersionString); } } - throw new IllegalArgumentException("Unknown Java version string: " + javaVersionString); + return ofJavaVersion(javaVersion); + } catch (NumberFormatException exception) { + throw new IllegalStateException("Failed to read Java version from: " + javaVersionString, exception); } } @@ -293,71 +263,12 @@ public static ClassFileVersion ofJavaVersionString(String javaVersionString, boo * @return A wrapper for the given Java class file version. */ public static ClassFileVersion ofJavaVersion(int javaVersion) { - return ofJavaVersion(javaVersion, OpenedClassReader.EXPERIMENTAL); - } - - /** - * Creates a class file version for a given major release of Java. Currently, all versions reaching from - * Java 1 to Java 9 are supported. - * - * @param javaVersion The Java version. - * @param experimental {@code true} if unknown Java versions should also be considered. - * @return A wrapper for the given Java class file version. - */ - public static ClassFileVersion ofJavaVersion(int javaVersion, boolean experimental) { - switch (javaVersion) { - case 1: - return JAVA_V1; - case 2: - return JAVA_V2; - case 3: - return JAVA_V3; - case 4: - return JAVA_V4; - case 5: - return JAVA_V5; - case 6: - return JAVA_V6; - case 7: - return JAVA_V7; - case 8: - return JAVA_V8; - case 9: - return JAVA_V9; - case 10: - return JAVA_V10; - case 11: - return JAVA_V11; - case 12: - return JAVA_V12; - case 13: - return JAVA_V13; - case 14: - return JAVA_V14; - case 15: - return JAVA_V15; - case 16: - return JAVA_V16; - case 17: - return JAVA_V17; - case 18: - return JAVA_V18; - case 19: - return JAVA_V19; - case 20: - return JAVA_V20; - case 21: - return JAVA_V21; - case 22: - return JAVA_V22; - case 23: - return JAVA_V23; - default: - if (experimental && javaVersion > 0) { - return new ClassFileVersion(BASE_VERSION + javaVersion); - } else { - throw new IllegalArgumentException("Unknown Java version: " + javaVersion); - } + if (javaVersion < 1) { + throw new IllegalArgumentException("Java version must be positive: " + javaVersion); + } else if (javaVersion - 1 < CLASS_FILE_VERSIONS.length) { + return CLASS_FILE_VERSIONS[javaVersion - 1]; + } else { + return new ClassFileVersion(BASE_VERSION + javaVersion); } } diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionOtherTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionOtherTest.java index bb0b008fbd..8d06104148 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionOtherTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionOtherTest.java @@ -88,6 +88,16 @@ public void testLatestVersion() throws Exception { assertThat(ClassFileVersion.latest().getMajorVersion(), is((short) value)); } + @Test(expected = IllegalArgumentException.class) + public void testNegativeVersion() throws Exception { + ClassFileVersion.ofJavaVersion(0); + } + + @Test(expected = IllegalArgumentException.class) + public void testOneDotTooNew() throws Exception { + ClassFileVersion.ofJavaVersionString("1.9"); + } + @Test(expected = IllegalArgumentException.class) public void testIllegalClassFile() throws Exception { ClassFileVersion.ofClassFile(new byte[0]); diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionTest.java index 33c8610b47..75c489c70a 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/ClassFileVersionTest.java @@ -66,21 +66,21 @@ public static Collection data() { {6, 6, Arrays.asList("1.6", "6"), Opcodes.V1_6, (short) 50, (short) 0, true, false, false}, {7, 7, Arrays.asList("1.7", "7"), Opcodes.V1_7, (short) 51, (short) 0, true, true, false}, {8, 8, Arrays.asList("1.8", "8"), Opcodes.V1_8, (short) 52, (short) 0, true, true, true}, - {9, 9, Arrays.asList("1.9", "9"), Opcodes.V9, (short) 53, (short) 0, true, true, true}, - {10, 10, Arrays.asList("1.10", "10"), Opcodes.V10, (short) 54, (short) 0, true, true, true}, - {11, 11, Arrays.asList("1.11", "11"), Opcodes.V11, (short) 55, (short) 0, true, true, true}, - {12, 12, Arrays.asList("1.12", "12"), Opcodes.V12, (short) 56, (short) 0, true, true, true}, - {13, 13, Arrays.asList("1.13", "13"), Opcodes.V13, (short) 57, (short) 0, true, true, true}, - {14, 14, Arrays.asList("1.14", "14"), Opcodes.V14, (short) 58, (short) 0, true, true, true}, - {15, 15, Arrays.asList("1.15", "15"), Opcodes.V15, (short) 59, (short) 0, true, true, true}, - {16, 16, Arrays.asList("1.16", "16"), Opcodes.V16, (short) 60, (short) 0, true, true, true}, - {17, 17, Arrays.asList("1.17", "17"), Opcodes.V17, (short) 61, (short) 0, true, true, true}, - {18, 18, Arrays.asList("1.18", "18"), Opcodes.V18, (short) 62, (short) 0, true, true, true}, - {19, 19, Arrays.asList("1.19", "19"), Opcodes.V19, (short) 63, (short) 0, true, true, true}, - {20, 20, Arrays.asList("1.20", "20"), Opcodes.V20, (short) 64, (short) 0, true, true, true}, - {21, 21, Arrays.asList("1.21", "21"), Opcodes.V21, (short) 65, (short) 0, true, true, true}, - {22, 22, Arrays.asList("1.22", "22"), Opcodes.V22, (short) 66, (short) 0, true, true, true}, - {23, 23, Arrays.asList("1.23", "23"), Opcodes.V23, (short) 67, (short) 0, true, true, true} + {9, 9, Collections.singletonList("9"), Opcodes.V9, (short) 53, (short) 0, true, true, true}, + {10, 10, Collections.singletonList("10"), Opcodes.V10, (short) 54, (short) 0, true, true, true}, + {11, 11, Collections.singletonList("11"), Opcodes.V11, (short) 55, (short) 0, true, true, true}, + {12, 12, Collections.singletonList("12"), Opcodes.V12, (short) 56, (short) 0, true, true, true}, + {13, 13, Collections.singletonList("13"), Opcodes.V13, (short) 57, (short) 0, true, true, true}, + {14, 14, Collections.singletonList("14"), Opcodes.V14, (short) 58, (short) 0, true, true, true}, + {15, 15, Collections.singletonList("15"), Opcodes.V15, (short) 59, (short) 0, true, true, true}, + {16, 16, Collections.singletonList("16"), Opcodes.V16, (short) 60, (short) 0, true, true, true}, + {17, 17, Collections.singletonList("17"), Opcodes.V17, (short) 61, (short) 0, true, true, true}, + {18, 18, Collections.singletonList("18"), Opcodes.V18, (short) 62, (short) 0, true, true, true}, + {19, 19, Collections.singletonList("19"), Opcodes.V19, (short) 63, (short) 0, true, true, true}, + {20, 20, Collections.singletonList("20"), Opcodes.V20, (short) 64, (short) 0, true, true, true}, + {21, 21, Collections.singletonList("21"), Opcodes.V21, (short) 65, (short) 0, true, true, true}, + {22, 22, Collections.singletonList("22"), Opcodes.V22, (short) 66, (short) 0, true, true, true}, + {23, 23, Collections.singletonList("23"), Opcodes.V23, (short) 67, (short) 0, true, true, true} }); }