1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2016 The Dagger Authors. 3*f585d8a3SJacky Wang * 4*f585d8a3SJacky Wang * Licensed under the Apache License, Version 2.0 (the "License"); 5*f585d8a3SJacky Wang * you may not use this file except in compliance with the License. 6*f585d8a3SJacky Wang * You may obtain a copy of the License at 7*f585d8a3SJacky Wang * 8*f585d8a3SJacky Wang * http://www.apache.org/licenses/LICENSE-2.0 9*f585d8a3SJacky Wang * 10*f585d8a3SJacky Wang * Unless required by applicable law or agreed to in writing, software 11*f585d8a3SJacky Wang * distributed under the License is distributed on an "AS IS" BASIS, 12*f585d8a3SJacky Wang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*f585d8a3SJacky Wang * See the License for the specific language governing permissions and 14*f585d8a3SJacky Wang * limitations under the License. 15*f585d8a3SJacky Wang */ 16*f585d8a3SJacky Wang 17*f585d8a3SJacky Wang package dagger.internal; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import static dagger.internal.Preconditions.checkNotNull; 20*f585d8a3SJacky Wang import static dagger.internal.Providers.asDaggerProvider; 21*f585d8a3SJacky Wang 22*f585d8a3SJacky Wang import dagger.Lazy; 23*f585d8a3SJacky Wang 24*f585d8a3SJacky Wang /** 25*f585d8a3SJacky Wang * A {@link Lazy} and {@link Provider} implementation that memoizes the value returned from a 26*f585d8a3SJacky Wang * delegate using the double-check idiom described in Item 71 of <i>Effective Java 2</i>. 27*f585d8a3SJacky Wang */ 28*f585d8a3SJacky Wang public final class DoubleCheck<T> implements Provider<T>, Lazy<T> { 29*f585d8a3SJacky Wang private static final Object UNINITIALIZED = new Object(); 30*f585d8a3SJacky Wang 31*f585d8a3SJacky Wang private volatile Provider<T> provider; 32*f585d8a3SJacky Wang private volatile Object instance = UNINITIALIZED; 33*f585d8a3SJacky Wang DoubleCheck(Provider<T> provider)34*f585d8a3SJacky Wang private DoubleCheck(Provider<T> provider) { 35*f585d8a3SJacky Wang assert provider != null; 36*f585d8a3SJacky Wang this.provider = provider; 37*f585d8a3SJacky Wang } 38*f585d8a3SJacky Wang 39*f585d8a3SJacky Wang @SuppressWarnings("unchecked") // cast only happens when result comes from the provider 40*f585d8a3SJacky Wang @Override get()41*f585d8a3SJacky Wang public T get() { 42*f585d8a3SJacky Wang Object result = instance; 43*f585d8a3SJacky Wang if (result == UNINITIALIZED) { 44*f585d8a3SJacky Wang synchronized (this) { 45*f585d8a3SJacky Wang result = instance; 46*f585d8a3SJacky Wang if (result == UNINITIALIZED) { 47*f585d8a3SJacky Wang result = provider.get(); 48*f585d8a3SJacky Wang instance = reentrantCheck(instance, result); 49*f585d8a3SJacky Wang /* Null out the reference to the provider. We are never going to need it again, so we 50*f585d8a3SJacky Wang * can make it eligible for GC. */ 51*f585d8a3SJacky Wang provider = null; 52*f585d8a3SJacky Wang } 53*f585d8a3SJacky Wang } 54*f585d8a3SJacky Wang } 55*f585d8a3SJacky Wang return (T) result; 56*f585d8a3SJacky Wang } 57*f585d8a3SJacky Wang 58*f585d8a3SJacky Wang /** 59*f585d8a3SJacky Wang * Checks to see if creating the new instance has resulted in a recursive call. If it has, and the 60*f585d8a3SJacky Wang * new instance is the same as the current instance, return the instance. However, if the new 61*f585d8a3SJacky Wang * instance differs from the current instance, an {@link IllegalStateException} is thrown. 62*f585d8a3SJacky Wang */ reentrantCheck(Object currentInstance, Object newInstance)63*f585d8a3SJacky Wang private static Object reentrantCheck(Object currentInstance, Object newInstance) { 64*f585d8a3SJacky Wang boolean isReentrant = currentInstance != UNINITIALIZED; 65*f585d8a3SJacky Wang if (isReentrant && currentInstance != newInstance) { 66*f585d8a3SJacky Wang throw new IllegalStateException("Scoped provider was invoked recursively returning " 67*f585d8a3SJacky Wang + "different results: " + currentInstance + " & " + newInstance + ". This is likely " 68*f585d8a3SJacky Wang + "due to a circular dependency."); 69*f585d8a3SJacky Wang } 70*f585d8a3SJacky Wang return newInstance; 71*f585d8a3SJacky Wang } 72*f585d8a3SJacky Wang 73*f585d8a3SJacky Wang /** Returns a {@link Provider} that caches the value from the given delegate provider. */ 74*f585d8a3SJacky Wang // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> delegate)" 75*f585d8a3SJacky Wang // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949. provider( P delegate)76*f585d8a3SJacky Wang public static <P extends dagger.internal.Provider<T>, T> dagger.internal.Provider<T> provider( 77*f585d8a3SJacky Wang P delegate) { 78*f585d8a3SJacky Wang checkNotNull(delegate); 79*f585d8a3SJacky Wang if (delegate instanceof DoubleCheck) { 80*f585d8a3SJacky Wang /* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped 81*f585d8a3SJacky Wang * binding, we shouldn't cache the value again. */ 82*f585d8a3SJacky Wang return delegate; 83*f585d8a3SJacky Wang } 84*f585d8a3SJacky Wang return new DoubleCheck<T>(delegate); 85*f585d8a3SJacky Wang } 86*f585d8a3SJacky Wang 87*f585d8a3SJacky Wang /** 88*f585d8a3SJacky Wang * Legacy javax version of the method to support libraries compiled with an older version of 89*f585d8a3SJacky Wang * Dagger. Do not use directly. 90*f585d8a3SJacky Wang */ 91*f585d8a3SJacky Wang @Deprecated provider( P delegate)92*f585d8a3SJacky Wang public static <P extends javax.inject.Provider<T>, T> javax.inject.Provider<T> provider( 93*f585d8a3SJacky Wang P delegate) { 94*f585d8a3SJacky Wang return provider(asDaggerProvider(delegate)); 95*f585d8a3SJacky Wang } 96*f585d8a3SJacky Wang 97*f585d8a3SJacky Wang /** Returns a {@link Lazy} that caches the value from the given provider. */ 98*f585d8a3SJacky Wang // This method is declared this way instead of "<T> Lazy<T> lazy(Provider<T> delegate)" 99*f585d8a3SJacky Wang // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949. lazy(P provider)100*f585d8a3SJacky Wang public static <P extends Provider<T>, T> Lazy<T> lazy(P provider) { 101*f585d8a3SJacky Wang if (provider instanceof Lazy) { 102*f585d8a3SJacky Wang @SuppressWarnings("unchecked") 103*f585d8a3SJacky Wang final Lazy<T> lazy = (Lazy<T>) provider; 104*f585d8a3SJacky Wang // Avoids memoizing a value that is already memoized. 105*f585d8a3SJacky Wang // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L 106*f585d8a3SJacky Wang // are different types using covariant return on get(). Right now this is used with 107*f585d8a3SJacky Wang // DoubleCheck<T> exclusively, which is implemented such that P and L are always 108*f585d8a3SJacky Wang // the same, so it will be fine for that case. 109*f585d8a3SJacky Wang return lazy; 110*f585d8a3SJacky Wang } 111*f585d8a3SJacky Wang return new DoubleCheck<T>(checkNotNull(provider)); 112*f585d8a3SJacky Wang } 113*f585d8a3SJacky Wang 114*f585d8a3SJacky Wang /** 115*f585d8a3SJacky Wang * Legacy javax version of the method to support libraries compiled with an older version of 116*f585d8a3SJacky Wang * Dagger. Do not use directly. 117*f585d8a3SJacky Wang */ lazy(P provider)118*f585d8a3SJacky Wang public static <P extends javax.inject.Provider<T>, T> Lazy<T> lazy(P provider) { 119*f585d8a3SJacky Wang return lazy(asDaggerProvider(provider)); 120*f585d8a3SJacky Wang } 121*f585d8a3SJacky Wang } 122