On 05/24/2016 01:41 PM, Peter Levart wrote:

It seems that my example will not help much. It also seems that the only problem with plain:

static final ClassValue<MetaClass> META_CLASS_CV = new ClassValue<MetaClass>() {
         protected MetaClass computeValue(Class<?> type) {
             return new MetaClass(type);

...is the fact that MetaClass is a class loaded by non-bootstrap class loader and that in case this is a Web app class loader, it prevents undeployment. Can you confirm that a MetaClass instance only references the 'type' Class<?> it is derived from (it's Methods, Fields, etc.) and never references objects from any child class loaders of the type's class loader?

If that is the case, then you could replace MetaClass with a generic data structure, composed of instances of bootstrap classes (HashMap, ArrayList, Object[], ...). That way, Groovy runtime class loader will not be "captured" by a reference from an aClass loaded by bootstrap class loader.

Is MetaClass a complicated data structure?

...peeking at Groovy sources, very much so. There's a solution though. Various Meta* classes in Groovy runtime reference at some point the reflective objects (Class, Method, Constructor, Field) describing the 'type' they are derived from.

Every reference to a Class object from such Meta* object should be wrapped in something like the following:

public final class ClassReference extends WeakReference<Class<?>>
    implements Supplier<Class<?>> {

private static final ConcurrentHashMap<ClassReference, ClassReference> MAP
        = new ConcurrentHashMap<>();
    private static final ReferenceQueue<Class<?>> QUEUE
        = new ReferenceQueue<>();

    public static ClassReference forClass(Class<?> clazz) {
        ClassReference oldRef;
        while ((oldRef = (ClassReference) QUEUE.poll()) != null) {
        ClassReference newRef = new ClassReference(clazz);
        oldRef = MAP.putIfAbsent(newRef, newRef);
        return oldRef == null ? newRef : oldRef;

    private final String name;
    private final int hash;

    private ClassReference(Class<?> clazz) {
        super(clazz, QUEUE);
        name = clazz.getName();
        hash = clazz.hashCode();

    public Class<?> get() {
        Class<?> clazz = super.get();
        if (clazz == null) {
            throw new IllegalStateException(
                "Class " + name + " has already been unloaded");
        return clazz;

    public int hashCode() {
        return hash;

    public boolean equals(Object obj) {
        Class<?> clazz;
        return obj == this ||
               (obj instanceof ClassReference &&
                (clazz = get()) != null &&
                clazz == ((ClassReference) obj).get());

Every reference to a Method should be wrapped in something like this:

public final class MethodReference implements Supplier<Method> {
    private static final ClassValue<Method[]> DECLARED_METHODS_CV =
        new ClassValue<Method[]>() {
            protected Method[] computeValue(Class<?> type) {
                return type.getDeclaredMethods();

    private final ClassReference declaringClassRef;
    private final int index;

    public MethodReference(Method method) {
        Class<?> declaringClass = method.getDeclaringClass();
        declaringClassRef = ClassReference.forClass(declaringClass);
        Method[] methods = DECLARED_METHODS_CV.get(declaringClass);
        index = Arrays.asList(methods).indexOf(method);

    public Method get() {
        return DECLARED_METHODS_CV.get(declaringClassRef.get())[index];

    public int hashCode() {
        return declaringClassRef.hashCode() * 31 + index;

    public boolean equals(Object obj) {
        return obj == this || (
            obj instanceof MethodReference &&
((MethodReference) obj).declaringClassRef == this.declaringClassRef &&
            ((MethodReference) obj).index == this.index

And similar with every reference to a Constructor or Field.

In addition, the MetaClass structure should be isolated from the class it is derived from with what I presented in the previous message (ClassValue<WeakReference<MetaClass>> + ArrayList<MetaClass> referenced from MetaClass static field)

Would that work?

Regards, Peter

mlvm-dev mailing list

Reply via email to