@SuppressWarnings("unchecked") // At runtime we know it's a Binding<Lazy<T>>. @Override public void attach(Linker linker) { delegate = (Binding<T>) linker.requestBinding(lazyKey, requiredBy, loader); }
/** * Links all bindings, injectable types and static injections. */ private Map<String, Binding<?>> linkEverything() { Map<String, Binding<?>> bindings = linker.fullyLinkedBindings(); if (bindings != null) { return bindings; } synchronized (linker) { if ((bindings = linker.fullyLinkedBindings()) != null) { return bindings; } linkStaticInjections(); linkInjectableTypes(); return linker.linkAll(); // Linker.linkAll() implicitly does Linker.linkRequested(). } }
assertLockHeld(); Binding<?> binding; while ((binding = toLink.poll()) != null) { createBinding(key, binding.requiredBy, deferred.classLoader, mustHaveInjections); resolvedBinding.setLibrary(binding.library()); resolvedBinding.setDependedOn(binding.dependedOn()); Binding<?> scopedBinding = scope(resolvedBinding); toLink.add(scopedBinding); putBinding(scopedBinding); } catch (InvalidBindingException e) { addError(e.type + " " + e.getMessage() + " required by " + binding.requiredBy); bindings.put(key, Binding.UNRESOLVED); } catch (UnsupportedOperationException e) { addError("Unsupported: " + e.getMessage() + " required by " + binding.requiredBy); bindings.put(key, Binding.UNRESOLVED); } catch (IllegalArgumentException e) { addError(e.getMessage() + " required by " + binding.requiredBy); bindings.put(key, Binding.UNRESOLVED); } catch (RuntimeException e) {
/** * @param classLoader the {@code ClassLoader} used to load dependent bindings. * @param injectableKey the key used to store the injectable type. This * is a provides key for interfaces and a members injection key for * other types. That way keys can always be created, even if the type * has no injectable constructor. * @param key the key to use when retrieving the binding. This may be a * regular (provider) key or a members key. */ private Binding<?> getInjectableTypeBinding( ClassLoader classLoader, String injectableKey, String key) { Class<?> moduleClass = null; for (DaggerObjectGraph graph = this; graph != null; graph = graph.base) { moduleClass = graph.injectableTypes.get(injectableKey); if (moduleClass != null) break; } if (moduleClass == null) { throw new IllegalArgumentException("No inject registered for " + injectableKey + ". You must explicitly add it to the 'injects' option in one of your modules."); } synchronized (linker) { Binding<?> binding = linker.requestBinding(key, moduleClass, classLoader, false, true); if (binding == null || !binding.isLinked()) { linker.linkRequested(); binding = linker.requestBinding(key, moduleClass, classLoader, false, true); } return binding; } } }
/** * Links all known bindings (whether requested or installed), plus all of their * transitive dependencies. This loads injectable types' bindings as necessary to fill in * the gaps. If this method has returned successfully at least once, all further * work is short-circuited. * * @throws AssertionError if this method is not called within a synchronized block which * holds this {@link Linker} as the lock object. */ public Map<String, Binding<?>> linkAll() { assertLockHeld(); if (linkedBindings != null) { return linkedBindings; } for (Binding<?> binding : bindings.values()) { if (!binding.isLinked()) { toLink.add(binding); } } linkRequested(); // This method throws if bindings are not resolvable/linkable. linkedBindings = Collections.unmodifiableMap(bindings); return linkedBindings; }
Linker linker = new Linker(null, new GraphAnalysisLoader(processingEnv), errorHandler); ? providerKey : GeneratorKeys.rawMembersKey(injectableType); linker.requestBinding(key, module.getQualifiedName().toString(), getClass().getClassLoader(), false, true); linker.installBindings(baseBindings); linker.installBindings(overrideBindings); for (GraphAnalysisStaticInjection staticInjection : staticInjections) { staticInjection.attach(linker); return linker.linkAll();
new Linker((base != null) ? base.linker : null, plugin, new ThrowingErrorHandler()); linker.installBindings(baseBindings); linker.installBindings(overrideBindings);
assertLockHeld(); Binding<?> jitBinding = createJitBinding(key, binding.requiredBy, mustBeInjectable); putBinding(jitBinding); } catch (Exception e) { if (e.getMessage() != null) { addError(e.getMessage() + " required by " + binding.requiredBy); bindings.put(key, Binding.UNRESOLVED); } else if (e instanceof RuntimeException) {
public static <T> void add(BindingsGroup bindings, String setKey, Binding<?> binding) { prepareSetBinding(bindings, setKey, binding).contributors.add(Linker.scope(binding)); }
private <T> void putBinding(Binding<T> binding) { binding = scope(binding); // At binding insertion time it's possible that another binding for the same // key to already exist. This occurs when an @Provides method returns a type T // and we also inject the members of that type. if (binding.provideKey != null) { putIfAbsent(bindings, binding.provideKey, binding); } if (binding.membersKey != null) { putIfAbsent(bindings, binding.membersKey, binding); } }
/** * Links all bindings, entry points and static injections. */ private Map<String, Binding<?>> linkEverything() { synchronized (linker) { linkStaticInjections(); linkEntryPoints(); return linker.linkAll(); } }
@Override public void injectStatics() { // We call linkStaticInjections() twice on purpose. The first time through // we request all of the bindings we need. The linker returns null for // bindings it doesn't have. Then we ask the linker to link all of those // requested bindings. Finally we call linkStaticInjections() again: this // time the linker won't return null because everything has been linked. synchronized (linker) { linkStaticInjections(); linker.linkRequested(); linkStaticInjections(); } for (Map.Entry<Class<?>, StaticInjection> entry : staticInjections.entrySet()) { entry.getValue().inject(); } }
private <T> void putBinding(final Binding<T> binding) { // At binding insertion time it's possible that another binding for the same // key to already exist. This occurs when an @Provides method returns a type T // and we also inject the members of that type. if (binding.provideKey != null) { putIfAbsent(bindings, binding.provideKey, binding); } if (binding.membersKey != null) { putIfAbsent(bindings, binding.membersKey, binding); } }
collectIncludesRecursively(rootModule, allModules); Linker linker = new Linker(null, new CompileTimePlugin(processingEnv), new ReportingErrorHandler(processingEnv, rootModule.getQualifiedName().toString())); linker.requestBinding(GeneratorKeys.rawMembersKey((TypeMirror) entryPoint), module.getQualifiedName().toString(), false); linker.installBindings(baseBindings); linker.installBindings(overrideBindings); return linker.linkAll();
private static ObjectGraph makeGraph(ObjectGraph base, Plugin plugin, Object... modules) { Map<String, Class<?>> entryPoints = new LinkedHashMap<String, Class<?>>(); Map<Class<?>, StaticInjection> staticInjections = new LinkedHashMap<Class<?>, StaticInjection>(); // Extract bindings in the 'base' and 'overrides' set. Within each set no // duplicates are permitted. Map<String, Binding<?>> baseBindings = new UniqueMap<String, Binding<?>>(); Map<String, Binding<?>> overrideBindings = new UniqueMap<String, Binding<?>>(); for (ModuleAdapter<?> moduleAdapter : getAllModuleAdapters(plugin, modules).values()) { for (String key : moduleAdapter.entryPoints) { entryPoints.put(key, moduleAdapter.getModule().getClass()); } for (Class<?> c : moduleAdapter.staticInjections) { staticInjections.put(c, null); } Map<String, Binding<?>> addTo = moduleAdapter.overrides ? overrideBindings : baseBindings; moduleAdapter.getBindings(addTo); } // Create a linker and install all of the user's bindings Linker linker = new Linker((base != null) ? base.linker : null, plugin, new ThrowingErrorHandler()); linker.installBindings(baseBindings); linker.installBindings(overrideBindings); return new ObjectGraph(base, linker, plugin, staticInjections, entryPoints); }
/** * @param entryPointKey the key used to store the entry point. This is always * a members injection key because those keys can always be created, even * if the type has no injectable constructor. * @param key the key to use when retrieving the binding. This may be a * regular (provider) key or a members key. */ private Binding<?> getEntryPointBinding(String entryPointKey, String key) { Class<?> moduleClass = null; for (ObjectGraph graph = this; graph != null; graph = graph.base) { moduleClass = graph.entryPoints.get(entryPointKey); if (moduleClass != null) break; } if (moduleClass == null) { throw new IllegalArgumentException("No entry point for " + entryPointKey + ". You must explicitly add an entry point to one of your modules."); } synchronized (linker) { Binding<?> binding = linker.requestBinding(key, moduleClass, false); if (binding == null || !binding.isLinked()) { linker.linkRequested(); binding = linker.requestBinding(key, moduleClass, false); } return binding; } } }
/** * Adds all bindings in {@code toInstall}. The caller must call either {@link * #linkAll} or {@link #requestBinding} and {@link #linkRequested} before the * bindings can be used. * * This method may only be called before {@link #linkAll()}. Subsequent calls to * {@link #installBindings(BindingsGroup)} will throw an {@link IllegalStateException}. */ public void installBindings(BindingsGroup toInstall) { if (linkedBindings != null) { throw new IllegalStateException("Cannot install further bindings after calling linkAll()."); } for (Map.Entry<String, ? extends Binding<?>> entry : toInstall.entrySet()) { bindings.put(entry.getKey(), scope(entry.getValue())); } }
/** * Links requested bindings and installed bindings, plus all of their * transitive dependencies. This creates JIT bindings as necessary to fill in * the gaps. * * @return all bindings known by this linker, which will all be linked. */ public Map<String, Binding<?>> linkAll() { for (Binding<?> binding : bindings.values()) { if (!binding.isLinked()) { toLink.add(binding); } } linkRequested(); return bindings; }