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


Reply via email to