diff --git a/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java b/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java index eda1d3f..f793e39 100644 --- a/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java +++ b/springloaded/src/main/java/org/springsource/loaded/agent/SpringPlugin.java @@ -65,12 +65,14 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP private Field classCacheField; private Field strongClassCacheField; private Field softClassCacheField; - + private Field declaredMethodsCacheField; private Field field_parameterNamesCache; // From LocalVariableTableParameterNameDiscoverer private boolean cachedIntrospectionResultsClassLoaded = false; - + private boolean reflectionUtilsClassLoaded = false; + private Class cachedIntrospectionResultsClass = null; + private Class reflectionUtilsClass = null; public boolean accept(String slashedTypeName, ClassLoader classLoader, ProtectionDomain protectionDomain, byte[] bytes) { // TODO take classloader into account? @@ -84,6 +86,10 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP if (slashedTypeName.equals("org/springframework/beans/CachedIntrospectionResults")) { cachedIntrospectionResultsClassLoaded = true; } + // Just interested in whether this type got loaded + if (slashedTypeName.equals("org/springframework/util/ReflectionUtils")) { + reflectionUtilsClassLoaded = true; + } return slashedTypeName.equals("org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter") || slashedTypeName.equals("org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping") || // 3.1 (support305 && slashedTypeName @@ -149,6 +155,7 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP public void reloadEvent(String typename, Class clazz, String versionsuffix) { removeClazzFromMethodResolverCache(clazz); + removeClazzFromDeclaredMethodsCache(clazz); clearCachedIntrospectionResults(clazz); reinvokeDetectHandlers(); // Spring 3.0 reinvokeInitHandlerMethods(); // Spring 3.1 @@ -177,7 +184,7 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP for (Object instance: instancesOf_LocalVariableTableParameterNameDiscoverer) { field_parameterNamesCache.setAccessible(true); try { - Map parameterNamesCache = (Map)field_parameterNamesCache.get(instance); + Map parameterNamesCache = (Map) field_parameterNamesCache.get(instance); Object o = parameterNamesCache.remove(clazz); if (debug) { System.out.println("ParameterNamesCache: Removed "+clazz.getName()+" from cache?"+(o!=null)); @@ -208,6 +215,41 @@ public class SpringPlugin implements LoadtimeInstrumentationPlugin, ReloadEventP } } + private void removeClazzFromDeclaredMethodsCache(Class clazz) { + if (reflectionUtilsClassLoaded) { + try { + // TODO not a fan of classloading like this + if (reflectionUtilsClass == null) { + // TODO what about two apps using reloading and diff versions of spring? + reflectionUtilsClass = clazz.getClassLoader().loadClass( + "org.springframework.util.ReflectionUtils"); + } + + if (declaredMethodsCacheField == null) { + try { + declaredMethodsCacheField = reflectionUtilsClass.getDeclaredField("declaredMethodsCache"); + } catch(NoSuchFieldException e) { + + } + + } + if(declaredMethodsCacheField != null) { + declaredMethodsCacheField.setAccessible(true); + Map m = (Map) declaredMethodsCacheField.get(null); + Object o = m.remove(clazz); + if (GlobalConfiguration.debugplugins) { + System.err.println("SpringPlugin: clearing ReflectionUtils.declaredMethodsCache for " + clazz.getName() + " removed=" + o); + } + } + + } catch (Exception e) { + if (GlobalConfiguration.debugplugins) { + e.printStackTrace(); + } + } + } + } + private void clearCachedIntrospectionResults(Class clazz) { if (cachedIntrospectionResultsClassLoaded) { try {