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