A Lazy and Provider implementation that memoizes the value returned from a delegate using the double-check idiom described in Item 71 of Effective Java 2 .
| 26 | * delegate using the double-check idiom described in Item 71 of <i>Effective Java 2</i>. |
| 27 | */ |
| 28 | public final class DoubleCheck<T> implements Provider<T>, Lazy<T> { |
| 29 | private static final Object UNINITIALIZED = new Object(); |
| 30 | |
| 31 | private volatile Provider<T> provider; |
| 32 | private volatile Object instance = UNINITIALIZED; |
| 33 | |
| 34 | private DoubleCheck(Provider<T> provider) { |
| 35 | assert provider != null; |
| 36 | this.provider = provider; |
| 37 | } |
| 38 | |
| 39 | @SuppressWarnings("unchecked") // cast only happens when result comes from the provider |
| 40 | @Override |
| 41 | public T get() { |
| 42 | Object result = instance; |
| 43 | if (result == UNINITIALIZED) { |
| 44 | synchronized (this) { |
| 45 | result = instance; |
| 46 | if (result == UNINITIALIZED) { |
| 47 | result = provider.get(); |
| 48 | /* Get the current instance and test to see if the call to provider.get() has resulted |
| 49 | * in a recursive call. If it returns the same instance, we'll allow it, but if the |
| 50 | * instances differ, throw. */ |
| 51 | Object currentInstance = instance; |
| 52 | if (currentInstance != UNINITIALIZED && currentInstance != result) { |
| 53 | throw new IllegalStateException("Scoped provider was invoked recursively returning " |
| 54 | + "different results: " + currentInstance + " & " + result + ". This is likely " |
| 55 | + "due to a circular dependency."); |
| 56 | } |
| 57 | instance = result; |
| 58 | /* Null out the reference to the provider. We are never going to need it again, so we |
| 59 | * can make it eligible for GC. */ |
| 60 | provider = null; |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | return (T) result; |
| 65 | } |
| 66 | |
| 67 | /** Returns a {@link Provider} that caches the value from the given delegate provider. */ |
| 68 | // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> delegate)" |
| 69 | // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949. |
| 70 | public static <P extends Provider<T>, T> Provider<T> provider(P delegate) { |
| 71 | checkNotNull(delegate); |
| 72 | if (delegate instanceof DoubleCheck) { |
| 73 | /* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped |
| 74 | * binding, we shouldn't cache the value again. */ |
| 75 | return delegate; |
| 76 | } |
| 77 | return new DoubleCheck<T>(delegate); |
| 78 | } |
| 79 | |
| 80 | /** Returns a {@link Lazy} that caches the value from the given provider. */ |
| 81 | // This method is declared this way instead of "<T> Lazy<T> lazy(Provider<T> delegate)" |
| 82 | // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949. |
| 83 | public static <P extends Provider<T>, T> Lazy<T> lazy(P provider) { |
| 84 | if (provider instanceof Lazy) { |
| 85 | @SuppressWarnings("unchecked") |
nothing calls this directly
no outgoing calls
no test coverage detected