package org.hotswap.agent.plugin.javabeans;
import org.hotswap.agent.annotation.LoadEvent;
import org.hotswap.agent.annotation.OnClassLoadEvent;
import org.hotswap.agent.annotation.Plugin;
import org.hotswap.agent.javassist.CtClass;
import org.hotswap.agent.logging.AgentLogger;
import org.hotswap.agent.util.ReflectionHelper;
/**
* JavaBeans plugin - flush java.beans.Introspector caches
*
* @author Vladimir Dvorak
*/
@Plugin(name = "JavaBeans",
description = "",
testedVersions = {"openjdk 1.7.0.95, 1.8.0_74"},
expectedVersions = {"All between openjdk 1.7 - 1.8"}
)
public class JavaBeansPlugin {
private static AgentLogger LOGGER = AgentLogger.getLogger(JavaBeansPlugin.class);
/**
* Flag to check reload status. In unit test we need to wait for reload
* finish before the test can continue. Set flag to true in the test class
* and wait until the flag is false again.
*/
public static boolean reloadFlag;
@OnClassLoadEvent(classNameRegexp = ".*", events = LoadEvent.REDEFINE, skipSynthetic=false)
public static void flushBeanIntrospectorsCaches(ClassLoader classLoader, CtClass ctClass) {
try {
LOGGER.debug("Flushing {}", ctClass.getName());
Class<?> clazz = classLoader.loadClass(ctClass.getName());
Class<?> threadGroupCtxClass = classLoader.loadClass("java.beans.ThreadGroupContext");
Class<?> introspectorClass = classLoader.loadClass("java.beans.Introspector");
Object declaredMethodCache = ReflectionHelper.get(null, introspectorClass, "declaredMethodCache");
synchronized (declaredMethodCache) {
Object contexts = ReflectionHelper.get(null, threadGroupCtxClass, "contexts");
Object table[] = (Object[]) ReflectionHelper.get(contexts, "table");
if (table != null) {
for (Object o: table) {
if (o != null) {
Object threadGroupContext = ReflectionHelper.get(o, "value");
if (threadGroupContext != null) {
LOGGER.trace("Removing from threadGroupContext");
ReflectionHelper.invoke(threadGroupContext, threadGroupCtxClass, "removeBeanInfo",
new Class[] { Class.class }, clazz);
}
}
}
}
LOGGER.trace("Removing class from declaredMethodCache.");
ReflectionHelper.invoke(declaredMethodCache, declaredMethodCache.getClass(), "put",
new Class[] { Object.class, Object.class }, clazz, null);
}
} catch (Exception e) {
LOGGER.error("classReload() exception {}.", e.getMessage());
} finally {
reloadFlag = false;
}
}
}