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