8169425: Values computed by a ClassValue should not strongly reference the ClassValue
Peter Levart
peter.levart at gmail.com
Wed Nov 9 13:15:58 UTC 2016
Hi Paul,
What do you think of introducing a static factory method in ClassValue
in addition to your @implNotes. The method would go like this (similar
to ThreadLocal.withInitial()):
public abstract class ClassValue<T> {
/**
* Creates a {@code ClassValue} instance which uses given {@code
factory}
* function for computing values associated with classes passed as
arguments
* to {@link #get} method. The given {@code factory} function will
only be
* <a href="../ref/package-summary.html#reachability"><em>weakly
reachable</em></a>
* from the created ClassValue instance, so one must ensure that is
is not Garbage
* Collected at least until the returned ClassValue is not used any
more.
* <p>
* Attempts to use created ClassValue instance to lazily calculate
another
* associated value after the given factory function is GCed will
result in
* {@link IllegalStateException} being thrown from the {@link #get}
method.
*
* @param factory the function to be used to produce values
associated with
* passed-in classes and created ClassValue instance
* @param <T> the type of values associated with created ClassValue
instance
* @return new instance of ClassValue, weakly referencing given
factory function.
* @since 9
*/
public static <T> ClassValue<T> withWeakFactory(
Function<? super Class<?>, T> factory)
{
WeakReference<Function<? super Class<?>, T>> factoryRef =
new WeakReference<>(factory);
return new ClassValue<T>() {
@Override
protected T computeValue(Class<?> type) {
Function<? super Class<?>, T> factory = factoryRef.get();
if (factory == null) {
throw new IllegalStateException(
"The value factory function has already been
GC(ed).");
}
return factory.apply(type);
}
};
}
@implNotes could point to this method with an example...
Regards, Peter
On 11/09/2016 01:49 PM, Peter Levart wrote:
> Or, better yet, using value factory Function instead of Supplier:
>
>
> public class WeakFactoryClassValue<T> extends ClassValue<T> {
> private final WeakReference<Function<? super Class<?>, ? extends
> T>> factoryRef;
>
> public WeakFactoryClassValue(Function<? super Class<?>, ? extends
> T> factory) {
> factoryRef = new WeakReference<>(factory);
> }
>
> @Override
> protected T computeValue(Class<?> type) {
> Function<? super Class<?>, ? extends T> factory =
> factoryRef.get();
> if (factory == null) {
> throw new IllegalStateException("Value factory function
> has already been GCed");
> }
> return factory.apply(type);
> }
> }
>
>
> The example would then read:
>
> public class MyApp {
> // make VALUE_FACTORY stay at least until MyApp class is alive
> private static final Function<Class<?>, Object> VALUE_FACTORY =
> clazz -> MyApp.CV;
>
> public static final ClassValue<Object> CV =
> new WeakFactoryClassValue<>(VALUE_FACTORY);
>
> public static void main(String[] args) {
> // this is OK
> CV.get(MyApp.class);
>
> // even this is OK, it makes CV reachable from Object.class,
> // but VALUE_FACTORY is only weakly reachable
> CV.get(Object.class);
> }
> }
>
>
>
> Regards, Peter
>
>
>
> On 11/09/2016 01:31 PM, Peter Levart wrote:
> > The above situation could be prevented by a special concrete > ClassValue implementation, provided by the platform (loaded by >
> bootstrap CL): > > public class WeakSupplierClassValue<T> extends
> ClassValue<T> { > private final WeakReference<Supplier<T>>
> supplierRef; > > public WeakSupplierClassValue(Supplier<T> supplier) {
> supplierRef = > new WeakReference<>(supplier); } > > @Override
> protected T computeValue(Class<?> type) { Supplier<T> > supplier =
> supplierRef.get(); if (supplier == null) { throw new >
> IllegalStateException("Supplier has already been GCed"); } return >
> supplier.get(); } } > > > ...with such utility class, one could
> rewrite above example to: > > public class MyApp { // make CV_SUPPLIER
> stay at least until MyApp > class is alive private static final
> Supplier<Object> CV_SUPPLIER = () > -> MyApp.CV; > > public static
> final ClassValue<Object> CV = new >
> WeakSupplierClassValue<>(CV_SUPPLIER); > > public static void
> main(String[] args) { // this is OK > CV.get(MyApp.class); > > // even
> this is OK, it makes CV reachable from Object.class, // but >
> CV_SUPPLIER is only weakly reachable CV.get(Object.class); } } > > >
> Regards, Peter
>
More information about the core-libs-dev
mailing list