diff --git a/devtools/pom.xml b/devtools/pom.xml index 236312274469c..3b99e2a36f5d9 100644 --- a/devtools/pom.xml +++ b/devtools/pom.xml @@ -27,6 +27,5 @@ maven gradle cli - reflection-agent diff --git a/devtools/reflection-agent/pom.xml b/devtools/reflection-agent/pom.xml deleted file mode 100644 index 9039be0559ea9..0000000000000 --- a/devtools/reflection-agent/pom.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - 4.0.0 - - - io.quarkus - quarkus-devtools-all - 999-SNAPSHOT - - - quarkus-devtools-reflection-agent - Quarkus - Dev tools - Reflection Agent - - A Java Agent that can detect the usage of Class.forName on classes that have not been registered for reflection. - To use this your Quarkus app must have been build with -Dquarkus.reflection.debug. - - - - reflection-agent - - - org.apache.maven.plugins - maven-jar-plugin - 2.3.1 - - - - io.quarkus.agent.ReflectionAgent - true - true - ${project.build.finalName}.jar - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - package - - shade - - - - - org.ow2.asm:* - - - - - org.objectweb.asm - io.quarkus.agent.org.objectweb.asm - - - - - - - - - - - - org.ow2.asm - asm - - - diff --git a/devtools/reflection-agent/src/main/java/io/quarkus/agent/ReflectionAgent.java b/devtools/reflection-agent/src/main/java/io/quarkus/agent/ReflectionAgent.java deleted file mode 100644 index d5bcbf53b0204..0000000000000 --- a/devtools/reflection-agent/src/main/java/io/quarkus/agent/ReflectionAgent.java +++ /dev/null @@ -1,144 +0,0 @@ -package io.quarkus.agent; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.instrument.ClassFileTransformer; -import java.lang.instrument.IllegalClassFormatException; -import java.nio.charset.StandardCharsets; -import java.security.ProtectionDomain; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -public class ReflectionAgent { - - private static volatile Set KNOWN_CLASSES; - - private static final Set warned = Collections.newSetFromMap(new ConcurrentHashMap<>()); - - public static void premain(java.lang.String s, java.lang.instrument.Instrumentation i) { - i.addTransformer(new ClassFileTransformer() { - @Override - public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, - ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { - if (className.startsWith("io/quarkus/agent") - || className.startsWith("java/") - || className.startsWith("javax/") - || className.startsWith("jakarta/") - || className.startsWith("jdk/") - || className.startsWith("sun/") - || className.startsWith("org/jboss/log")) { - return null; - } - try { - AtomicBoolean modified = new AtomicBoolean(false); - ClassReader reader = new ClassReader(className); - ClassWriter writer = new ClassWriter(reader, Opcodes.ASM7); - reader.accept(new ClassVisitor(Opcodes.ASM7, writer) { - @Override - public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, - String[] exceptions) { - MethodVisitor existing = super.visitMethod(access, name, descriptor, signature, exceptions); - return new MethodVisitor(Opcodes.ASM7, existing) { - @Override - public void visitMethodInsn(int opcode, String owner, String name, String descriptor, - boolean isInterface) { - if (owner.equals("java/lang/Class") && name.equals("forName")) { - modified.set(true); - super.visitMethodInsn(opcode, ReflectionAgent.class.getName().replace('.', '/'), name, - descriptor, isInterface); - } else if (owner.equals("java/lang/ClassLoader") && name.equals("loadClass")) { - modified.set(true); - if (descriptor.equals("(Ljava/lang/String;)Ljava/lang/Class;")) { - super.visitMethodInsn(Opcodes.INVOKESTATIC, - ReflectionAgent.class.getName().replace('.', '/'), name, - "(Ljava/lang/ClassLoader;Ljava/lang/String;)Ljava/lang/Class;", false); - } else { - super.visitMethodInsn(Opcodes.INVOKESTATIC, - ReflectionAgent.class.getName().replace('.', '/'), name, - "(Ljava/lang/ClassLoader;Ljava/lang/String;Z)Ljava/lang/Class;", false); - } - } else { - super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); - } - } - }; - } - }, 0); - if (modified.get()) { - return writer.toByteArray(); - } - return null; - - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - } - - public static Class loadClass(ClassLoader loader, String className) throws ClassNotFoundException { - handleClass(className); - return loader.loadClass(className); - } - - public static Class loadClass(ClassLoader loader, String className, boolean resolve) throws ClassNotFoundException { - handleClass(className); - return loader.loadClass(className); - } - - public static Class forName(String className) throws ClassNotFoundException { - handleClass(className); - //this is not technically correct, for Quarkus we know there is only one class loader - //once we are on JDK11 we can revisit - return Class.forName(className, false, Thread.currentThread().getContextClassLoader()); - } - - private static void handleClass(String className) { - if (KNOWN_CLASSES == null) { - Set known = new HashSet<>(); - try (InputStream in = Thread.currentThread().getContextClassLoader() - .getResourceAsStream("META-INF/reflective-classes.txt")) { - BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - String line; - while ((line = reader.readLine()) != null) { - known.add(line); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - KNOWN_CLASSES = Collections.unmodifiableSet(known); - } - if (!KNOWN_CLASSES.contains(className)) { - if (!warned.contains(className)) { - boolean valid = true; - for (StackTraceElement s : new RuntimeException().getStackTrace()) { - if (s.getMethodName().equals("")) { - valid = false; - break; - } - } - if (valid) { - System.err.println("REFLECTIVE CLASS NOT REGISTERED: " + className); - } - warned.add(className); - } - } - } - - public static Class forName(String name, boolean initialize, - ClassLoader loader) throws ClassNotFoundException { - handleClass(name); - return Class.forName(name, initialize, loader); - } -}