From fa713979c0b891fc06e58f25187f669146c454de Mon Sep 17 00:00:00 2001 From: gregw Date: Tue, 20 Oct 2020 13:29:30 +0200 Subject: [PATCH 1/3] Fixes #5475 Scan for updated ASM version Scan for the highest known ASM version so we can always run on latest JVM if the ASM jar is updated. --- .../jetty/annotations/AnnotationParser.java | 79 +++++-------------- 1 file changed, 20 insertions(+), 59 deletions(-) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 0ba214d44c33..0dc814a1f756 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -35,7 +35,6 @@ import org.eclipse.jetty.util.JavaVersion; import org.eclipse.jetty.util.Loader; -import org.eclipse.jetty.util.ManifestUtils; import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiReleaseJarFile; import org.eclipse.jetty.util.StringUtil; @@ -48,7 +47,6 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; /** * AnnotationParser @@ -71,80 +69,43 @@ public class AnnotationParser { private static final Logger LOG = Log.getLogger(AnnotationParser.class); - private static final int ASM_OPCODE_VERSION = Opcodes.ASM9; //compatibility of api - private static final String ASM_OPCODE_VERSION_STR = "ASM9"; + private static final int ASM_VERSION = asmVersion(); /** * Map of classnames scanned and the first location from which scan occurred */ protected Map _parsedClassNames = new ConcurrentHashMap<>(); private final int _javaPlatform; - private int _asmVersion; + private final int _asmVersion; /** * Determine the runtime version of asm. * * @return the org.objectweb.asm.Opcode matching the runtime version of asm. */ - public static int asmVersion() + private static int asmVersion() { - int asmVersion = ASM_OPCODE_VERSION; - String version = ManifestUtils.getVersion(Opcodes.class).orElse(null); - if (version == null) + // We need to search for the highest known ASM version. + // If we run with a lower than known ASM version, then if run on a JVM with new language features + // we will get UnsupportedOperationsExceptions, even if the version of ASM is updated to support them. + // If we run with a higher than known ASM version, then we will get a unknown version exception. + // So we need the Goldilocks version! + int asmVersion = 7; + while (true) { - LOG.warn("Unknown ASM version, assuming {}", ASM_OPCODE_VERSION_STR); - } - else - { - int dot = version.indexOf('.'); - version = version.substring(0, (dot < 0 ? version.length() : dot)).trim(); try { - int v = Integer.parseInt(version); - switch (v) - { - case 4: - { - asmVersion = Opcodes.ASM4; - break; - } - case 5: - { - asmVersion = Opcodes.ASM5; - break; - } - case 6: - { - asmVersion = Opcodes.ASM6; - break; - } - case 7: - { - asmVersion = Opcodes.ASM7; - break; - } - case 8: - { - asmVersion = Opcodes.ASM8; - break; - } - case 9: - { - asmVersion = Opcodes.ASM9; - break; - } - default: - { - LOG.warn("Unrecognized ASM version, assuming {}", ASM_OPCODE_VERSION_STR); - } - } + int nextVersion = asmVersion + 1; + new ClassVisitor(nextVersion << 16, null) + {}; + asmVersion = nextVersion; } - catch (NumberFormatException e) + catch (Throwable th) { - LOG.warn("Unable to parse ASM version, assuming {}", ASM_OPCODE_VERSION_STR); + break; } } - return asmVersion; + return asmVersion << 16; } /** @@ -490,7 +451,7 @@ public AnnotationVisitor visitAnnotation(String desc, boolean visible) */ public class MyClassVisitor extends ClassVisitor { - int _asmVersion; + final int _asmVersion; final Resource _containingResource; final Set _handlers; ClassInfo _ci; @@ -569,7 +530,7 @@ public AnnotationParser() */ public AnnotationParser(int javaPlatform) { - _asmVersion = asmVersion(); + _asmVersion = ASM_VERSION; if (javaPlatform == 0) javaPlatform = JavaVersion.VERSION.getPlatform(); _javaPlatform = javaPlatform; @@ -581,7 +542,7 @@ public AnnotationParser(int javaPlatform, int asmVersion) javaPlatform = JavaVersion.VERSION.getPlatform(); _javaPlatform = javaPlatform; if (asmVersion == 0) - asmVersion = ASM_OPCODE_VERSION; + asmVersion = ASM_VERSION; _asmVersion = asmVersion; } From a3e363234083d4acd71ff03f515b4aa5701846fe Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Tue, 20 Oct 2020 09:34:38 -0500 Subject: [PATCH 2/3] Issue #5475 - Changing ASM API version lookup to use Reflection against ASM Opcodes. Signed-off-by: Joakim Erdfelt --- .../jetty/annotations/AnnotationParser.java | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 0dc814a1f756..02f7e2f826a1 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -47,6 +48,7 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; /** * AnnotationParser @@ -81,31 +83,36 @@ public class AnnotationParser /** * Determine the runtime version of asm. * - * @return the org.objectweb.asm.Opcode matching the runtime version of asm. + * @return the {@link org.objectweb.asm.Opcodes} ASM value matching the runtime version of asm. */ private static int asmVersion() { - // We need to search for the highest known ASM version. - // If we run with a lower than known ASM version, then if run on a JVM with new language features - // we will get UnsupportedOperationsExceptions, even if the version of ASM is updated to support them. - // If we run with a higher than known ASM version, then we will get a unknown version exception. - // So we need the Goldilocks version! - int asmVersion = 7; - while (true) + // Find the highest available ASM version on the runtime/classpath, because + // if we run with a lower than available ASM version, against a class with + // new language features we'll get an UnsupportedOperationException, even if + // the ASM version supports the new language features. + // Also, if we run with a higher than available ASM version, we'll get + // an IllegalArgumentException from org.objectweb.asm.ClassVisitor. + // So must find exactly the maximum ASM api version available. + + Optional asmVersion = Arrays.stream(Opcodes.class.getFields()).sequential() + .filter((f) -> f.getName().matches("ASM[0-9]+")) + .map((f) -> f.getName().substring(3)) + .map(Integer::parseInt) + .max(Integer::compareTo); + + if (!asmVersion.isPresent()) + throw new IllegalStateException("Invalid " + Opcodes.class.getName()); + + int asmFieldId = asmVersion.get(); + try { - try - { - int nextVersion = asmVersion + 1; - new ClassVisitor(nextVersion << 16, null) - {}; - asmVersion = nextVersion; - } - catch (Throwable th) - { - break; - } + return (int)Opcodes.class.getField("ASM" + asmFieldId).get(null); + } + catch (Throwable e) + { + throw new IllegalStateException(e); } - return asmVersion << 16; } /** From 7155066d4a12a1466d05cdaedf37a58595519123 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Tue, 20 Oct 2020 10:07:43 -0500 Subject: [PATCH 3/3] Issue #5475 - Adding debug log output for asmVersion detect Signed-off-by: Joakim Erdfelt --- .../java/org/eclipse/jetty/annotations/AnnotationParser.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 02f7e2f826a1..8e2c3dad7336 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -107,7 +107,10 @@ private static int asmVersion() int asmFieldId = asmVersion.get(); try { - return (int)Opcodes.class.getField("ASM" + asmFieldId).get(null); + String fieldName = "ASM" + asmFieldId; + if (LOG.isDebugEnabled()) + LOG.debug("Using ASM API from {}.{}", Opcodes.class.getName(), fieldName); + return (int)Opcodes.class.getField(fieldName).get(null); } catch (Throwable e) {