I have two questions:
1. Has there been any discussion of allowing WeakReference (and the
corresponding JNI NewWeakGlobalRef) to accept value objects in a
future revision of the value objects feature? Obviously in this case,
the referent would never be cleared by GC, but it would allow common
code to be able to continue to function. There are some "gotchas"
here. For example, would such a reference ever be automatically
enqueued on a ReferenceQueue? If so, when and how would that work?
Indeed, we have discussed this! The first question is "what should the
semantics of WR(value) be". And there are actually at least three
reasonable answers, and the choice of which is the "most right" is not
as obvious as it might seem.
1. As you suggest, WR(value) is just never cleared.
2. A WR(value) is always immediately cleared.
3. A WR(value) can be cleared only when any identities held within it
are weakly reachable.
(1) is the first one everyone comes to, because it avoids cases like the
one you've encountered -- but doesn't really implement any sort of
weakness. (2) is justifiable but likely useless in most cases. (3) is
actually principled; it asks "could this value be reconstituted", and
that is only true if its fields can be reconstituted, which is always
true for pure values and true for identities if they are reachable. But
(3) is obviously very intrusive for the GC, and it is not obvious how
helpful in practice it is.
Since there is not an obviously "right and useful and reasonably
implementable answer", right now WRs just say "nope" when presented with
a value object.
2. What is the best advice for applications or libraries like JavaFX
to deal with this? The current approach we are considering is
described in [2] and [3], where we would create a WeakReferenceWrapper
class that either creates and stores a reference (if the object has
identity) or stores the object itself (if it is either null or does
not have identity). Its get method would return either ref.get() or
obj. Is there a better approach?
This is what we recommend for the time being; it simulates semantics (1)
above, but dumps the bookkeeping in your lap, which is obviously not great.
Longer-term, we observe that many of the uses of WR are through
WeakHashMap, and it would be reasonable to specify a policy to the WHM
constructor that says what to do: throw, follow (1), follow (2), etc. A
WRWrapper could then offer the same set of choices. This would leave WR
in its current, simple state. I suspect there will never be one answer
that does what all applications expect of WR(value), which is why a
multiplicity of potential policies, implemented from outside of WR,
seems likely.