Details
-
Improvement
-
Status: Closed
-
Minor
-
Resolution: Fixed
-
1.0-beta-4
-
None
-
None
-
Any application-server environment with multiple classloaders. In particular, Resin.
Description
The current MetaClass and MetaClassRegistry do not integrate as cleanly in application server environments as they could.
In particular, groovy classes loaded by an application server classloader are stored in a static hashmap, which can prevent GC when the classloaders are dropped.
In addition, dynamically created classes are not loaded properly, but are attempted to be loaded in a global classloader context (which, of course does not work.)
The solutions are:
1) Make the MetaClassRegistry.metaClasses Map as WeakHashMap to allow dropped classes to be garbage collected.
2) Add a MetaClassRegistry.loaderMap to create GroovyClassLoaders on top of the context ClassLoader, instead of dropping to a global GroovyClassLoader.
Assuming this change is implemented, Resin can use groovy generated classes exactly as any other class. (Which would be very, very cool.)
— MetaClassRegistry.java.orig 2004-04-02 19:21:52.000000000 -0800
+++ MetaClassRegistry.java 2004-04-02 19:17:41.000000000 -0800
@@ -48,7 +48,7 @@
import java.beans.IntrospectionException;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.HashMap;
+import java.util.WeakHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -64,9 +64,10 @@
- @version $Revision: 1.10 $
*/
public class MetaClassRegistry {
- private Map metaClasses = Collections.synchronizedMap(new HashMap());
+ private Map metaClasses = Collections.synchronizedMap(new WeakHashMap());
private boolean useAccessible;
private GroovyClassLoader loader = new GroovyClassLoader(getClass().getClassLoader());
+ private Map loaderMap = Collections.synchronizedMap(new WeakHashMap());
public MetaClassRegistry() {
this(true);
@@ -118,12 +119,33 @@
/**
- A helper class to load meta class bytecode into the class loader
*/
- public Class loadClass(String name, byte[] bytecode) throws ClassNotFoundException {
- return loader.loadClass(name, bytecode);
+ public Class loadClass(ClassLoader loader, String name, byte[] bytecode) throws ClassNotFoundException { + return getGroovyLoader(loader).loadClass(name, bytecode); }
- public Class loadClass(String name) throws ClassNotFoundException {
- return loader.loadClass(name);
+ public Class loadClass(ClassLoader loader, String name) throws ClassNotFoundException { + return getGroovyLoader(loader).loadClass(name); + }+
+ private GroovyClassLoader getGroovyLoader(ClassLoader loader)
+ {
+ if (loader instanceof GroovyClassLoader)
+ return (GroovyClassLoader) loader;
+
+ synchronized (loaderMap)Unknown macro: {+ GroovyClassLoader groovyLoader;+ groovyLoader = (GroovyClassLoader) loaderMap.get(loader);+ if (groovyLoader == null) { + if (loader == null || loader == getClass().getClassLoader()) + groovyLoader = this.loader; + else + groovyLoader = new GroovyClassLoader(loader); + + loaderMap.put(loader, groovyLoader); + }++ return groovyLoader;+ }}
/**
— MetaClass.java.orig 2004-04-02 19:21:41.000000000 -0800
+++ MetaClass.java 2004-04-02 18:53:43.000000000 -0800
@@ -1448,7 +1448,7 @@
GroovyClassLoader gloader = (GroovyClassLoader) loader;
return gloader.loadClass(name, bytecode);
}
- return registry.loadClass(name, bytecode);
+ return registry.loadClass(loader, name, bytecode);
}
protected Class loadReflectorClass(String name) throws ClassNotFoundException
{ @@ -1457,7 +1457,7 @@ GroovyClassLoader gloader = (GroovyClassLoader) loader; return gloader.loadClass(name); }- return registry.loadClass(name);
+ return registry.loadClass(loader, name);
}
public List getMethods() {