如何用 Java 仪器替换 class 的新仪器?
How do I replace a class with new one with Java instrumentation?
我需要创建一个 java 代理,当它被启用时它获取一个 jar 文件的路径作为参数然后它替换任何加载的 class jar 文件中的那个如果他们名称匹配。
例如,我们有一个名为 com.something.ClassTest 的 class 应用程序。现在,如果提到的 jar(不在 class 路径中)有一个 class 与 com.something.ClassTest 完全相同的名称,我想用 jar 中的那个替换它。
我有这个 class 变压器,但不确定它是否正确。我收到消息 Class not found.
的 IOException
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(classNames.contains(className.replace("/", "."))) {
System.out.format("\n==> Found %s \n", className);
try {
Class c = urlClassLoader.loadClass(className.replace("/", "."));
InputStream is = urlClassLoader.getResourceAsStream(className.replace("/", "."));
System.out.println("Loaded class " + c);
ClassReader reader = new ClassReader(is);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
byte[] content = writer.toByteArray();
System.out.println("Redifned " + new String(content));
System.out.println("Orig " + new String(classfileBuffer));
ClassDefinition cd = new ClassDefinition(c, content);
instrumentation.redefineClasses(cd);
return content;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnmodifiableClassException e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
我得到的错误是在实例化 ClassReader 的那一行。我猜这个错误是因为 urlClassloader 在当前 class loader 的层次结构之下......但我不知道我还能怎么做。
这是 URL class 加载初始化的代码
public SimpleClassTransformer(Instrumentation instrumentation, String jarFileName) {
this.jarFileName = jarFileName;
if(jarFileName != null) {
JarFile jarFile = null;
try {
jarFile = new JarFile(this.jarFileName);
Enumeration e = jarFile.entries();
System.out.println("Jar file: " + this.jarFileName);
URL[] urls = { new URL("jar:file:" + this.jarFileName+"!/") };
urlClassLoader = URLClassLoader.newInstance(urls);
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class")){
continue;
}
// -6 because of .class
String jarClassName = je.getName().substring(0,je.getName().length()-6);
jarClassName = jarClassName.replace('/', '.');
System.out.println("Adding class " + jarClassName);
this.classNames.add(jarClassName);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在 premain() 方法中实例化转换器时设置检测。我试图避免使用 Javassist。你能帮我解决这个问题吗?
这是我得到的异常:
java.io.IOException: Class not found
at jdk.internal.org.objectweb.asm.ClassReader.readClass(ClassReader.java:484)
at jdk.internal.org.objectweb.asm.ClassReader.<init>(ClassReader.java:453)
at com.agent.SimpleClassTransformer.transform(SimpleClassTransformer.java:79)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access0(URLClassLoader.java:73)
at java.net.URLClassLoader.run(URLClassLoader.java:368)
at java.net.URLClassLoader.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:394)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1397)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1344)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:597)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1445)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:445)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:415)
at org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DefaultDispatcherServletCondition.checkServlets(DispatcherServletAutoConfiguration.java:141)
at org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DefaultDispatcherServletCondition.getMatchOutcome(DispatcherServletAutoConfiguration.java:131)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:102)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:203)
at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:336)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:248)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:231)
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:509)
at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:454)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:185)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:321)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:677)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:519)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:295)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101)
==== 编辑 ====
修复 url class 加载程序的问题后,我现在收到 Spring 尝试刷新其上下文时发生的错误:
TestClass has been compiled by a more recent version of the Java Runtime (class file version 0.0), this version of the Java Runtime only recognizes class file versions up to 52.0
- 您的
UrlClassLoader
应该包含您要从中加载 class 的 jar 文件。
- 如果class已经加载,则无法重新加载。
- 检测和重新定义 class 仅在 class 加载到 JVM 时有效。
代码看起来不错,但您需要仔细检查 urlClassLoader 是否包含您要从中加载的 jar 文件 class 并且 jar 具有所需的 class.
您可以调试应用程序以确保上述条件。
解决您的问题的另一种方法是使用认可的目录。
保留 class 您想在库中加载的内容,并提供 -Djava.endorsed.dirs=<directory_path>
作为程序的 JVM 参数。
加载 classes 时,JVM 首先检查此目录中的 class 可用性,如果未找到,它将检查应用程序 classes。
这工作得很好,没有任何问题,也没有任何编码。
我设法解决了这个问题。如果有人遇到同样的问题,那就是问题所在:
我正在使用 ClassReader 和 ClassWriter。出于某种原因,ClassWriter 正在填充字节码,也许我将已编译的 class 传递给 class 编写器是我的错误,但无论如何以下代码:
ClassReader reader = new ClassReader(is);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
byte[] content = writer.toByteArray();
替换为:
InputStream is = urlClassLoader.getResourceAsStream(className + ".class");
byte[] content = new byte[is.available()];
is.read(content);
System.out.println ("Original class version: " + ((classfileBuffer[6]&0xff)<<8 | (classfileBuffer[7]&0xff)));
System.out.println ("Redefined class version: " + ((content[6]&0xff)<<8 | (content[7]&0xff)));
如您所见,我正在使用 InputStream 直接检索字节码。这解决了问题,如果您有兴趣,Spring 很好地检测到差异并刷新了上下文。
==== 编辑 ====
我注意到在这里使用 URLClassLoader 是不可靠的,因为某些原因,它可能 return 应用程序本身中已经加载的 class 而不是 JAR 文件中的 class。它是随机的,有时 returns 是 jar 中的 class,有时是原始的 class,所以我决定删除 URLClassLoader,而是将 class 文件作为 InputStream 而获取遍历jar文件。
这是我的转换器的最终代码,供任何需要它的人使用:
public class JarFileClassTransformer implements ClassFileTransformer {
private String jarFileName = null;
protected Map<String, InputStream> classNames = new HashMap<>();
static Instrumentation instrumentation = null;
/**
* Constructor.
* @param jarFileName
*/
public JarFileClassTransformer(String jarFileName) {
this.jarFileName = jarFileName;
File file = new File(jarFileName);
System.out.println("Jar file '" + this.jarFileName + "' " + (file.exists() ? "exists" : "doesn't exists!"));
if(file.exists()) {
try {
JarFile jarFile = new JarFile(file);
Enumeration e = jarFile.entries();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class")){
continue;
}
// -6 because of .class
String jarClassName = je.getName().substring(0,je.getName().length()-6);
jarClassName = jarClassName.replace('/', '.');
System.out.println("Adding class " + jarClassName);
this.classNames.put(jarClassName, jarFile.getInputStream(je));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(classNames.containsKey(className.replace("/", "."))) {
System.out.format("\n==> Found %s to replace with the existing version\n", className);
try {
Class c = loader.loadClass(className.replace("/", "."));
System.out.println("Existing class: " + c);
InputStream is = classNames.get(className.replace("/", "."));
byte[] content = new byte[is.available()];
is.read(content);
System.out.println("Original class version: " + ((classfileBuffer[6]&0xff)<<8 | (classfileBuffer[7]&0xff)));
System.out.println("Redefined class version: " + ((content[6]&0xff)<<8 | (content[7]&0xff)));
System.out.println("Original bytecode: " + new String(classfileBuffer));
System.out.println("Redefined byte code: " + new String(content));
ClassDefinition cd = new ClassDefinition(c, content);
instrumentation.redefineClasses(cd);
return content;
} catch (Throwable e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
}
我需要创建一个 java 代理,当它被启用时它获取一个 jar 文件的路径作为参数然后它替换任何加载的 class jar 文件中的那个如果他们名称匹配。
例如,我们有一个名为 com.something.ClassTest 的 class 应用程序。现在,如果提到的 jar(不在 class 路径中)有一个 class 与 com.something.ClassTest 完全相同的名称,我想用 jar 中的那个替换它。
我有这个 class 变压器,但不确定它是否正确。我收到消息 Class not found.
的 IOException @Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(classNames.contains(className.replace("/", "."))) {
System.out.format("\n==> Found %s \n", className);
try {
Class c = urlClassLoader.loadClass(className.replace("/", "."));
InputStream is = urlClassLoader.getResourceAsStream(className.replace("/", "."));
System.out.println("Loaded class " + c);
ClassReader reader = new ClassReader(is);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
byte[] content = writer.toByteArray();
System.out.println("Redifned " + new String(content));
System.out.println("Orig " + new String(classfileBuffer));
ClassDefinition cd = new ClassDefinition(c, content);
instrumentation.redefineClasses(cd);
return content;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnmodifiableClassException e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
我得到的错误是在实例化 ClassReader 的那一行。我猜这个错误是因为 urlClassloader 在当前 class loader 的层次结构之下......但我不知道我还能怎么做。
这是 URL class 加载初始化的代码
public SimpleClassTransformer(Instrumentation instrumentation, String jarFileName) {
this.jarFileName = jarFileName;
if(jarFileName != null) {
JarFile jarFile = null;
try {
jarFile = new JarFile(this.jarFileName);
Enumeration e = jarFile.entries();
System.out.println("Jar file: " + this.jarFileName);
URL[] urls = { new URL("jar:file:" + this.jarFileName+"!/") };
urlClassLoader = URLClassLoader.newInstance(urls);
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class")){
continue;
}
// -6 because of .class
String jarClassName = je.getName().substring(0,je.getName().length()-6);
jarClassName = jarClassName.replace('/', '.');
System.out.println("Adding class " + jarClassName);
this.classNames.add(jarClassName);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在 premain() 方法中实例化转换器时设置检测。我试图避免使用 Javassist。你能帮我解决这个问题吗?
这是我得到的异常:
java.io.IOException: Class not found
at jdk.internal.org.objectweb.asm.ClassReader.readClass(ClassReader.java:484)
at jdk.internal.org.objectweb.asm.ClassReader.<init>(ClassReader.java:453)
at com.agent.SimpleClassTransformer.transform(SimpleClassTransformer.java:79)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
at java.net.URLClassLoader.access0(URLClassLoader.java:73)
at java.net.URLClassLoader.run(URLClassLoader.java:368)
at java.net.URLClassLoader.run(URLClassLoader.java:362)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:394)
at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1397)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1344)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:597)
at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1445)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:445)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:415)
at org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DefaultDispatcherServletCondition.checkServlets(DispatcherServletAutoConfiguration.java:141)
at org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration$DefaultDispatcherServletCondition.getMatchOutcome(DispatcherServletAutoConfiguration.java:131)
at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:102)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:203)
at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:336)
at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:248)
at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:231)
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:509)
at org.springframework.context.annotation.ConfigurationClassParser.processDeferredImportSelectors(ConfigurationClassParser.java:454)
at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:185)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:321)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:243)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:273)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:98)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:677)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:519)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:295)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101)
==== 编辑 ====
修复 url class 加载程序的问题后,我现在收到 Spring 尝试刷新其上下文时发生的错误:
TestClass has been compiled by a more recent version of the Java Runtime (class file version 0.0), this version of the Java Runtime only recognizes class file versions up to 52.0
- 您的
UrlClassLoader
应该包含您要从中加载 class 的 jar 文件。 - 如果class已经加载,则无法重新加载。
- 检测和重新定义 class 仅在 class 加载到 JVM 时有效。
代码看起来不错,但您需要仔细检查 urlClassLoader 是否包含您要从中加载的 jar 文件 class 并且 jar 具有所需的 class.
您可以调试应用程序以确保上述条件。
解决您的问题的另一种方法是使用认可的目录。
保留 class 您想在库中加载的内容,并提供 -Djava.endorsed.dirs=<directory_path>
作为程序的 JVM 参数。
加载 classes 时,JVM 首先检查此目录中的 class 可用性,如果未找到,它将检查应用程序 classes。 这工作得很好,没有任何问题,也没有任何编码。
我设法解决了这个问题。如果有人遇到同样的问题,那就是问题所在:
我正在使用 ClassReader 和 ClassWriter。出于某种原因,ClassWriter 正在填充字节码,也许我将已编译的 class 传递给 class 编写器是我的错误,但无论如何以下代码:
ClassReader reader = new ClassReader(is);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
byte[] content = writer.toByteArray();
替换为:
InputStream is = urlClassLoader.getResourceAsStream(className + ".class");
byte[] content = new byte[is.available()];
is.read(content);
System.out.println ("Original class version: " + ((classfileBuffer[6]&0xff)<<8 | (classfileBuffer[7]&0xff)));
System.out.println ("Redefined class version: " + ((content[6]&0xff)<<8 | (content[7]&0xff)));
如您所见,我正在使用 InputStream 直接检索字节码。这解决了问题,如果您有兴趣,Spring 很好地检测到差异并刷新了上下文。
==== 编辑 ====
我注意到在这里使用 URLClassLoader 是不可靠的,因为某些原因,它可能 return 应用程序本身中已经加载的 class 而不是 JAR 文件中的 class。它是随机的,有时 returns 是 jar 中的 class,有时是原始的 class,所以我决定删除 URLClassLoader,而是将 class 文件作为 InputStream 而获取遍历jar文件。 这是我的转换器的最终代码,供任何需要它的人使用:
public class JarFileClassTransformer implements ClassFileTransformer {
private String jarFileName = null;
protected Map<String, InputStream> classNames = new HashMap<>();
static Instrumentation instrumentation = null;
/**
* Constructor.
* @param jarFileName
*/
public JarFileClassTransformer(String jarFileName) {
this.jarFileName = jarFileName;
File file = new File(jarFileName);
System.out.println("Jar file '" + this.jarFileName + "' " + (file.exists() ? "exists" : "doesn't exists!"));
if(file.exists()) {
try {
JarFile jarFile = new JarFile(file);
Enumeration e = jarFile.entries();
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if(je.isDirectory() || !je.getName().endsWith(".class")){
continue;
}
// -6 because of .class
String jarClassName = je.getName().substring(0,je.getName().length()-6);
jarClassName = jarClassName.replace('/', '.');
System.out.println("Adding class " + jarClassName);
this.classNames.put(jarClassName, jarFile.getInputStream(je));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if(classNames.containsKey(className.replace("/", "."))) {
System.out.format("\n==> Found %s to replace with the existing version\n", className);
try {
Class c = loader.loadClass(className.replace("/", "."));
System.out.println("Existing class: " + c);
InputStream is = classNames.get(className.replace("/", "."));
byte[] content = new byte[is.available()];
is.read(content);
System.out.println("Original class version: " + ((classfileBuffer[6]&0xff)<<8 | (classfileBuffer[7]&0xff)));
System.out.println("Redefined class version: " + ((content[6]&0xff)<<8 | (content[7]&0xff)));
System.out.println("Original bytecode: " + new String(classfileBuffer));
System.out.println("Redefined byte code: " + new String(content));
ClassDefinition cd = new ClassDefinition(c, content);
instrumentation.redefineClasses(cd);
return content;
} catch (Throwable e) {
e.printStackTrace();
}
}
return classfileBuffer;
}
}