1*f585d8a3SJacky Wang /* 2*f585d8a3SJacky Wang * Copyright (C) 2019 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.hilt; 18*f585d8a3SJacky Wang 19*f585d8a3SJacky Wang import dagger.hilt.internal.GeneratedComponent; 20*f585d8a3SJacky Wang import dagger.hilt.internal.GeneratedComponentManager; 21*f585d8a3SJacky Wang import dagger.hilt.internal.Preconditions; 22*f585d8a3SJacky Wang import dagger.hilt.internal.TestSingletonComponent; 23*f585d8a3SJacky Wang import java.lang.annotation.Annotation; 24*f585d8a3SJacky Wang import javax.annotation.Nonnull; 25*f585d8a3SJacky Wang 26*f585d8a3SJacky Wang /** Static utility methods for accessing objects through entry points. */ 27*f585d8a3SJacky Wang public final class EntryPoints { 28*f585d8a3SJacky Wang private static final String EARLY_ENTRY_POINT = "dagger.hilt.android.EarlyEntryPoint"; 29*f585d8a3SJacky Wang 30*f585d8a3SJacky Wang /** 31*f585d8a3SJacky Wang * Returns the entry point interface given a component or component manager. Note that this 32*f585d8a3SJacky Wang * performs an unsafe cast and so callers should be sure that the given component/component 33*f585d8a3SJacky Wang * manager matches the entry point interface that is given. 34*f585d8a3SJacky Wang * 35*f585d8a3SJacky Wang * @param component The Hilt-generated component instance. For convenience, also takes component 36*f585d8a3SJacky Wang * manager instances as well. 37*f585d8a3SJacky Wang * @param entryPoint The interface marked with {@link dagger.hilt.EntryPoint}. The {@link 38*f585d8a3SJacky Wang * dagger.hilt.InstallIn} annotation on this entry point should match the component argument 39*f585d8a3SJacky Wang * above. 40*f585d8a3SJacky Wang */ 41*f585d8a3SJacky Wang // Note that the input is not statically declared to be a Component or ComponentManager to make 42*f585d8a3SJacky Wang // this method easier to use, since most code will use this with an Application or Activity type. 43*f585d8a3SJacky Wang @Nonnull get(Object component, Class<T> entryPoint)44*f585d8a3SJacky Wang public static <T> T get(Object component, Class<T> entryPoint) { 45*f585d8a3SJacky Wang if (component instanceof GeneratedComponent) { 46*f585d8a3SJacky Wang if (component instanceof TestSingletonComponent) { 47*f585d8a3SJacky Wang // @EarlyEntryPoint only has an effect in test environment, so we shouldn't fail in 48*f585d8a3SJacky Wang // non-test cases. In addition, some of the validation requires the use of reflection, which 49*f585d8a3SJacky Wang // we don't want to do in non-test cases anyway. 50*f585d8a3SJacky Wang Preconditions.checkState( 51*f585d8a3SJacky Wang !hasAnnotationReflection(entryPoint, EARLY_ENTRY_POINT), 52*f585d8a3SJacky Wang "Interface, %s, annotated with @EarlyEntryPoint should be called with " 53*f585d8a3SJacky Wang + "EarlyEntryPoints.get() rather than EntryPoints.get()", 54*f585d8a3SJacky Wang entryPoint.getCanonicalName()); 55*f585d8a3SJacky Wang } 56*f585d8a3SJacky Wang // Unsafe cast. There is no way for this method to know that the correct component was used. 57*f585d8a3SJacky Wang return entryPoint.cast(component); 58*f585d8a3SJacky Wang } else if (component instanceof GeneratedComponentManager) { 59*f585d8a3SJacky Wang return get(((GeneratedComponentManager<?>) component).generatedComponent(), entryPoint); 60*f585d8a3SJacky Wang } else { 61*f585d8a3SJacky Wang throw new IllegalStateException( 62*f585d8a3SJacky Wang String.format( 63*f585d8a3SJacky Wang "Given component holder %s does not implement %s or %s", 64*f585d8a3SJacky Wang component.getClass(), GeneratedComponent.class, GeneratedComponentManager.class)); 65*f585d8a3SJacky Wang } 66*f585d8a3SJacky Wang } 67*f585d8a3SJacky Wang 68*f585d8a3SJacky Wang // Note: This method uses reflection but it should only be called in test environments. hasAnnotationReflection(Class<?> clazz, String annotationName)69*f585d8a3SJacky Wang private static boolean hasAnnotationReflection(Class<?> clazz, String annotationName) { 70*f585d8a3SJacky Wang for (Annotation annotation : clazz.getAnnotations()) { 71*f585d8a3SJacky Wang if (annotation.annotationType().getCanonicalName().contentEquals(annotationName)) { 72*f585d8a3SJacky Wang return true; 73*f585d8a3SJacky Wang } 74*f585d8a3SJacky Wang } 75*f585d8a3SJacky Wang return false; 76*f585d8a3SJacky Wang } 77*f585d8a3SJacky Wang EntryPoints()78*f585d8a3SJacky Wang private EntryPoints() {} 79*f585d8a3SJacky Wang } 80