-
1. Re: Composite Map key and weak reference
jason.greene May 20, 2008 10:14 AM (in response to alesj)So I take it the annotation refs point to annotations on the class ref?
I could see a couple of options:- You could use a WeakIdentityHM using a Class ref as the key, and a nested normal HM using a key which has an array of weak annotation refs. This would then be wrapped in a delegate which emulates the composite key behavior.
- Use a normal map, of any kind, and extend WeakReference to have an additional strong reference field, that points to your composite key class. Use this special reference for both the Class ref and all of the annotation refs. These are then registered in a ref queue, which is processed to remove gc'd entries periodically when accessing the map (by using the key reference). For this to work the key must do an identity check before comparing its contents (since the contents are gone during cleanup). If the map is concurrent you could do this cleanup in a separate thread.
- You could use a WeakIdentityHM using a Class ref as the key, and a nested normal HM using a key which has an array of weak annotation refs. This would then be wrapped in a delegate which emulates the composite key behavior.
-
2. Re: Composite Map key and weak reference
brian.stansberry May 20, 2008 10:20 AM (in response to alesj)I believe Jason's #2 is what I was thinking about in our chat discussion. A rough impl:
package hacks; import java.lang.annotation.Annotation; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; public class Key { private static final ReferenceQueue refQueue = new ReferenceQueue(); private final KeyRef keyRef; private final WeakReference<Annotation>[] annotations; public Key(Class clazz, Annotation[] annotations) { this.keyRef = new KeyRef(this, clazz, refQueue); this.annotations = new WeakReference[annotations.length]; for (int j = 0; j < annotations.length; j++) { this.annotations[j]= new WeakReference<Annotation>(annotations[j]); } } @Override public boolean equals(Object obj) { if (obj instanceof Key) { Key other = (Key) obj; Class clazz = keyRef.get(); Class otherClass = other.keyRef.get(); if (clazz == null || otherClass == null) { cleanKeyRefs(); return false; } else { if (shouldCleanKeyRefs()) cleanKeyRefs(); return clazz.equals(otherClass); // need to add in annotations } } return false; } /** Allows optimization; i.e. change to only poll the queue every X invocations */ private boolean shouldCleanKeyRefs() { return true; } /** * Poll the reference queue and clear the strong ref to Key from all * reference objects. This allows the Key to get removed from * WeakHashMap. */ private void cleanKeyRefs() { Reference ref = null; while ((ref = refQueue.poll()) != null) { ((KeyRef) ref).key = null; } } private static class KeyRef extends WeakReference<Class> { private Key key; KeyRef(Key key, Class clazz, ReferenceQueue queue) { super(clazz, queue); this.key = key; } } }
-
3. Re: Composite Map key and weak reference
brian.stansberry May 20, 2008 10:23 AM (in response to alesj)Oh, but my class above is intended to be passed as a key to WeakHashMap. The ReferenceQueue polling will remove the only strong ref to the Key, at which point the WeakHashMap will do its normal thing and make the Key/value pair eligible for removal.
-
4. Re: Composite Map key and weak reference
alesj May 20, 2008 10:31 AM (in response to alesj)"jason.greene@jboss.com" wrote:
So I take it the annotation refs point to annotations on the class ref?
Not really.
But some of class's annotations might be equal to that annotations.
I'm using this with WebBeans kind of matching:@Red @Blue @Inject public void setFoo(Foo foo)
where class might have@Red @Blue @Green public class RGBFoo implement Foo
The code is here - but the caching is currently wrong :-)
-
http://anonsvn.jboss.org/repos/jbossas/projects/microcontainer/trunk/kernel/src/main/org/jboss/kernel/plugins/annotations/wb/WBInjectionResolver.java -
5. Re: Composite Map key and weak reference
jason.greene May 20, 2008 10:49 AM (in response to alesj)"alesj" wrote:
"jason.greene@jboss.com" wrote:
So I take it the annotation refs point to annotations on the class ref?
Not really.
But some of class's annotations might be equal to that annotations.
Ah, ok, then you don't want the first option. -
6. Re: Composite Map key and weak reference
jason.greene May 20, 2008 10:52 AM (in response to alesj)"bstansberry@jboss.com" wrote:
Oh, but my class above is intended to be passed as a key to WeakHashMap. The ReferenceQueue polling will remove the only strong ref to the Key, at which point the WeakHashMap will do its normal thing and make the Key/value pair eligible for removal.
IMO it would be better to connect the logic to the map, then the entry is cleared in one pass, and you aren't tied to a particular map implementation. -
7. Re: Composite Map key and weak reference
adrian.brock May 20, 2008 11:08 AM (in response to alesj)I don't really understand.
If the class references the annotations then all you need to do is make sure
you have something like:WeakHashMap<Class<?>, WeakValueHashMap<List<Annotation>, Whatever>>
You then need to do a double lookup
Pseudo code (need to check nulls):Whatever w = map.get(clazz).get(annotations);
This will basically remove the reference when either the initial class or the
"Whatever" instance is GCed.
It don't think it really matters if you have hard refernces on the Annotations classes
in the List since that will also be true while the original Class/ClassLoader or
Whatever holds references?
Of course if you really want to be safe, you could try to create a
WeakCompositeKeyHashMap
which removes the entry when any of the elements in the composite key
gets GCed. -
8. Re: Composite Map key and weak reference
alesj May 20, 2008 11:18 AM (in response to alesj)"adrian@jboss.org" wrote:
If the class references the annotations then all you need to do is make sure you have something like:
No, it doesn't.
See my response to Jason."adrian@jboss.org" wrote:
Of course if you really want to be safe, you could try to create a
WeakCompositeKeyHashMap
which removes the entry when any of the elements in the composite key
gets GCed.
Yeah, that I could figure. :-)
See my initial post:"alesj" wrote:
Is there an easier way than rewriting the whole WeakHM (or some similar construct)? -
9. Re: Composite Map key and weak reference
alesj May 21, 2008 9:36 AM (in response to alesj)"bstansberry@jboss.com" wrote:
Oh, but my class above is intended to be passed as a key to WeakHashMap. The ReferenceQueue polling will remove the only strong ref to the Key, at which point the WeakHashMap will do its normal thing and make the Key/value pair eligible for removal.
Hmmm ... trying to put your code into real life showed some issues.
The way you do your refQueue is wrong. :-)
And I don't see how you can do it right.
Since what you have to pass into WeakReference as Queue instance is the initial queue of actual type of your WeakReference - the type that's gonna be GCed - in our case the Class ref.
But in that case we cannot do thisprivate void cleanKeyRefs() { Reference ref = null; while ((ref = refQueue.poll()) != null) { ((KeyRef) ref).key = null; } }
I'll try to do WeakCompositeKeyMap, doing something similar as what we do in WeakValueHashMap. -
10. Re: Composite Map key and weak reference
jason.greene May 21, 2008 8:00 PM (in response to alesj)Ales did you read the second suggestion I posted.
-
11. Re: Composite Map key and weak reference
alesj May 22, 2008 1:38 AM (in response to alesj)"jason.greene@jboss.com" wrote:
Ales did you read the second suggestion I posted.
Sure. ;-)
But I also think I'm wrong with my previous post, as Brian's impl should work as well.
If not, I'll impl it your (2nd) way. -
12. Re: Composite Map key and weak reference
alesj May 22, 2008 6:12 AM (in response to alesj)"bstansberry@jboss.com" wrote:
public class Key { private static final ReferenceQueue refQueue = new ReferenceQueue(); private final KeyRef keyRef; private final WeakReference<Annotation>[] annotations; public Key(Class clazz, Annotation[] annotations) { this.keyRef = new KeyRef(this, clazz, refQueue); this.annotations = new WeakReference[annotations.length]; for (int j = 0; j < annotations.length; j++) { this.annotations[j]= new WeakReference<Annotation>(annotations[j]); } }
Do I really need these annotations to be wrapped in weak refs?
Wouldn't they get immediately gced?
Or if I just leave them strong, my whole Key instance will be gc candidate the moment I nullify it in herewhile ((ref = refQueue.poll()) != null) { ((KeyRef) ref).key = null; }
since nothing else now has a strongly ref on it. -
13. Re: Composite Map key and weak reference
brian.stansberry May 22, 2008 10:52 AM (in response to alesj)I just wrapped them in WeakRefs in case they would leak the Class' classloader, preventing gc of the Class. Don't know whether in your scenario they will or not.
TBH, I didn't think much at all about the annotations; I was focused on the Class; just threw in the annotation array because you said your key had one.