xref: /aosp_15_r20/external/dagger2/java/dagger/internal/DoubleCheck.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
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