Home | History | Annotate | Download | only in internal
      1 /*
      2  * Copyright (C) 2014 Google, Inc.
      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 package dagger.internal;
     17 
     18 import dagger.Lazy;
     19 import javax.inject.Provider;
     20 
     21 /**
     22  * A basic {@link Lazy} implementation that memoizes the value returned from a {@link Provider}
     23  * using the double-check idiom described in Effective Java 2: Item 71.
     24  *
     25  * @author Gregory Kick
     26  * @since 2.0
     27  */
     28 // TODO(gak): Unify the duplicated code between this and ScopedProvider.
     29 public final class DoubleCheckLazy<T> implements Lazy<T> {
     30   private static final Object UNINITIALIZED = new Object();
     31 
     32   private final Provider<T> provider;
     33   private volatile Object instance = UNINITIALIZED;
     34 
     35   private DoubleCheckLazy(Provider<T> provider) {
     36     assert provider != null;
     37     this.provider = provider;
     38   }
     39 
     40   @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
     41   @Override
     42   public T get() {
     43     // to suppress it.
     44     Object result = instance;
     45     if (result == UNINITIALIZED) {
     46       synchronized (this) {
     47         result = instance;
     48         if (result == UNINITIALIZED) {
     49           instance = result = provider.get();
     50         }
     51       }
     52     }
     53     return (T) result;
     54   }
     55 
     56   public static <T> Lazy<T> create(Provider<T> provider) {
     57     if (provider == null) {
     58       throw new NullPointerException();
     59     }
     60     if (provider instanceof Lazy) {
     61       @SuppressWarnings("unchecked")
     62       final Lazy<T> lazy = (Lazy<T>) provider;
     63       // Avoids memoizing a value that is already memoized.
     64       // NOTE: There is a pathological case where Provider<P> may implement Lazy<L>, but P and L
     65       // are different types using covariant return on get(). Right now this is used with
     66       // ScopedProvider<T> exclusively, which is implemented such that P and L are always the same
     67       // so it will be fine for that case.
     68       return lazy;
     69     }
     70     return new DoubleCheckLazy<T>(provider);
     71   }
     72 }
     73