106 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			Java
		
	
	
	
| /*
 | |
|  * Copyright (C) 2016 The Dagger Authors.
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  * http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| package dagger.internal;
 | |
| 
 | |
| import static dagger.internal.Preconditions.checkNotNull;
 | |
| 
 | |
| import dagger.Lazy;
 | |
| import javax.inject.Provider;
 | |
| 
 | |
| /**
 | |
|  * A {@link Lazy} and {@link Provider} implementation that memoizes the value returned from a
 | |
|  * delegate using the double-check idiom described in Item 71 of <i>Effective Java 2</i>.
 | |
|  */
 | |
| public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
 | |
|   private static final Object UNINITIALIZED = new Object();
 | |
| 
 | |
|   private volatile Provider<T> provider;
 | |
|   private volatile Object instance = UNINITIALIZED;
 | |
| 
 | |
|   private DoubleCheck(Provider<T> provider) {
 | |
|     assert provider != null;
 | |
|     this.provider = provider;
 | |
|   }
 | |
| 
 | |
|   @SuppressWarnings("unchecked") // cast only happens when result comes from the provider
 | |
|   @Override
 | |
|   public T get() {
 | |
|     Object result = instance;
 | |
|     if (result == UNINITIALIZED) {
 | |
|       synchronized (this) {
 | |
|         result = instance;
 | |
|         if (result == UNINITIALIZED) {
 | |
|           result = provider.get();
 | |
|           instance = reentrantCheck(instance, result);
 | |
|           /* Null out the reference to the provider. We are never going to need it again, so we
 | |
|            * can make it eligible for GC. */
 | |
|           provider = null;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return (T) result;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Checks to see if creating the new instance has resulted in a recursive call. If it has, and the
 | |
|    * new instance is the same as the current instance, return the instance. However, if the new
 | |
|    * instance differs from the current instance, an {@link IllegalStateException} is thrown.
 | |
|    */
 | |
|   public static Object reentrantCheck(Object currentInstance, Object newInstance) {
 | |
|     boolean isReentrant = !(currentInstance == UNINITIALIZED
 | |
|         // This check is needed for fastInit's implementation, which uses MemoizedSentinel types.
 | |
|         || currentInstance instanceof MemoizedSentinel);
 | |
| 
 | |
|     if (isReentrant && currentInstance != newInstance) {
 | |
|       throw new IllegalStateException("Scoped provider was invoked recursively returning "
 | |
|           + "different results: " + currentInstance + " & " + newInstance + ". This is likely "
 | |
|           + "due to a circular dependency.");
 | |
|     }
 | |
|     return newInstance;
 | |
|   }
 | |
| 
 | |
|   /** Returns a {@link Provider} that caches the value from the given delegate provider. */
 | |
|   // This method is declared this way instead of "<T> Provider<T> provider(Provider<T> delegate)"
 | |
|   // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
 | |
|   public static <P extends Provider<T>, T> Provider<T> provider(P delegate) {
 | |
|     checkNotNull(delegate);
 | |
|     if (delegate instanceof DoubleCheck) {
 | |
|       /* This should be a rare case, but if we have a scoped @Binds that delegates to a scoped
 | |
|        * binding, we shouldn't cache the value again. */
 | |
|       return delegate;
 | |
|     }
 | |
|     return new DoubleCheck<T>(delegate);
 | |
|   }
 | |
| 
 | |
|   /** Returns a {@link Lazy} that caches the value from the given provider. */
 | |
|   // This method is declared this way instead of "<T> Lazy<T> lazy(Provider<T> delegate)"
 | |
|   // to work around an Eclipse type inference bug: https://github.com/google/dagger/issues/949.
 | |
|   public static <P extends Provider<T>, T> Lazy<T> lazy(P provider) {
 | |
|     if (provider instanceof Lazy) {
 | |
|       @SuppressWarnings("unchecked")
 | |
|       final Lazy<T> lazy = (Lazy<T>) provider;
 | |
|       // Avoids memoizing a value that is already memoized.
 | |
|       // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L
 | |
|       // are different types using covariant return on get(). Right now this is used with
 | |
|       // DoubleCheck<T> exclusively, which is implemented such that P and L are always
 | |
|       // the same, so it will be fine for that case.
 | |
|       return lazy;
 | |
|     }
 | |
|     return new DoubleCheck<T>(checkNotNull(provider));
 | |
|   }
 | |
| }
 |