Internal: Remove child injectors from guice
This change removes the ability for guice to have child injectors (and the entire concept of parent injectors) from our fork of guice. The methodology for removing was simple: I removed createChildInjector, and continued to remove methods and members that were unused until my head was spinning. The motivation for this change is to limit what our fork of guice gives us access to, so we don't regress and start adding back more complicated uses.
This commit is contained in:
parent
dea00a0b16
commit
7e59181e58
|
@ -38,12 +38,6 @@ import java.util.Map;
|
|||
* An injector can also {@link #injectMembers(Object) inject the dependencies} of
|
||||
* already-constructed instances. This can be used to interoperate with objects created by other
|
||||
* frameworks or services.
|
||||
* <p>
|
||||
* Injectors can be {@link #createChildInjector(Iterable) hierarchical}. Child injectors inherit
|
||||
* the configuration of their parent injectors, but the converse does not hold.
|
||||
* <p>
|
||||
* The injector's {@link #getBindings() internal bindings} are available for introspection. This
|
||||
* enables tools and extensions to operate on an injector reflectively.
|
||||
*
|
||||
* @author crazybob@google.com (Bob Lee)
|
||||
* @author jessewilson@google.com (Jesse Wilson)
|
||||
|
@ -87,41 +81,6 @@ public interface Injector {
|
|||
*/
|
||||
<T> MembersInjector<T> getMembersInjector(Class<T> type);
|
||||
|
||||
/**
|
||||
* Returns all explicit bindings.
|
||||
* <p>
|
||||
* The returned map does not include bindings inherited from a {@link #getParent() parent
|
||||
* injector}, should one exist. The returned map is guaranteed to iterate (for example, with
|
||||
* its {@link java.util.Map#entrySet()} iterator) in the order of insertion. In other words,
|
||||
* the order in which bindings appear in user Modules.
|
||||
* <p>
|
||||
* This method is part of the Guice SPI and is intended for use by tools and extensions.
|
||||
*/
|
||||
Map<Key<?>, Binding<?>> getBindings();
|
||||
|
||||
/**
|
||||
* Returns the binding for the given injection key. This will be an explicit bindings if the key
|
||||
* was bound explicitly by a module, or an implicit binding otherwise. The implicit binding will
|
||||
* be created if necessary.
|
||||
* <p>
|
||||
* This method is part of the Guice SPI and is intended for use by tools and extensions.
|
||||
*
|
||||
* @throws ConfigurationException if this injector cannot find or create the binding.
|
||||
*/
|
||||
<T> Binding<T> getBinding(Key<T> key);
|
||||
|
||||
/**
|
||||
* Returns the binding for the given type. This will be an explicit bindings if the injection key
|
||||
* was bound explicitly by a module, or an implicit binding otherwise. The implicit binding will
|
||||
* be created if necessary.
|
||||
* <p>
|
||||
* This method is part of the Guice SPI and is intended for use by tools and extensions.
|
||||
*
|
||||
* @throws ConfigurationException if this injector cannot find or create the binding.
|
||||
* @since 2.0
|
||||
*/
|
||||
<T> Binding<T> getBinding(Class<T> type);
|
||||
|
||||
/**
|
||||
* Returns all explicit bindings for {@code type}.
|
||||
* <p>
|
||||
|
@ -166,45 +125,4 @@ public interface Injector {
|
|||
* @throws ProvisionException if there was a runtime failure while providing an instance.
|
||||
*/
|
||||
<T> T getInstance(Class<T> type);
|
||||
|
||||
/**
|
||||
* Returns this injector's parent, or {@code null} if this is a top-level injector.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
Injector getParent();
|
||||
|
||||
/**
|
||||
* Returns a new injector that inherits all state from this injector. All bindings, scopes,
|
||||
* interceptors and type converters are inherited -- they are visible to the child injector.
|
||||
* Elements of the child injector are not visible to its parent.
|
||||
* <p>
|
||||
* Just-in-time bindings created for child injectors will be created in an ancestor injector
|
||||
* whenever possible. This allows for scoped instances to be shared between injectors. Use
|
||||
* explicit bindings to prevent bindings from being shared with the parent injector.
|
||||
* <p>
|
||||
* No key may be bound by both an injector and one of its ancestors. This includes just-in-time
|
||||
* bindings. The lone exception is the key for {@code Injector.class}, which is bound by each
|
||||
* injector to itself.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
Injector createChildInjector(Iterable<? extends Module> modules);
|
||||
|
||||
/**
|
||||
* Returns a new injector that inherits all state from this injector. All bindings, scopes,
|
||||
* interceptors and type converters are inherited -- they are visible to the child injector.
|
||||
* Elements of the child injector are not visible to its parent.
|
||||
* <p>
|
||||
* Just-in-time bindings created for child injectors will be created in an ancestor injector
|
||||
* whenever possible. This allows for scoped instances to be shared between injectors. Use
|
||||
* explicit bindings to prevent bindings from being shared with the parent injector.
|
||||
* <p>
|
||||
* No key may be bound by both an injector and one of its ancestors. This includes just-in-time
|
||||
* bindings. The lone exception is the key for {@code Injector.class}, which is bound by each
|
||||
* injector to itself.
|
||||
*
|
||||
* @since 2.0
|
||||
*/
|
||||
Injector createChildInjector(Module... modules);
|
||||
}
|
||||
|
|
|
@ -74,15 +74,6 @@ class InjectorBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parent of the injector to-be-constructed. As a side effect, this sets this injector's
|
||||
* stage to the stage of {@code parent}.
|
||||
*/
|
||||
InjectorBuilder parentInjector(InjectorImpl parent) {
|
||||
shellBuilder.parent(parent);
|
||||
return stage(parent.getInstance(Stage.class));
|
||||
}
|
||||
|
||||
InjectorBuilder addModules(Iterable<? extends Module> modules) {
|
||||
shellBuilder.addModules(modules);
|
||||
return this;
|
||||
|
@ -102,11 +93,6 @@ class InjectorBuilder {
|
|||
initializeStatically();
|
||||
}
|
||||
|
||||
// If we're in the tool stage, stop here. Don't eagerly inject or load anything.
|
||||
if (stage == Stage.TOOL) {
|
||||
return new ToolStageInjector(primaryInjector());
|
||||
}
|
||||
|
||||
injectDynamically();
|
||||
|
||||
return primaryInjector();
|
||||
|
@ -217,92 +203,4 @@ class InjectorBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Injector} exposed to users in {@link Stage#TOOL}.
|
||||
*/
|
||||
static class ToolStageInjector implements Injector {
|
||||
private final Injector delegateInjector;
|
||||
|
||||
ToolStageInjector(Injector delegateInjector) {
|
||||
this.delegateInjector = delegateInjector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void injectMembers(Object o) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.injectMembers(Object) is not supported in Stage.TOOL");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Key<?>, Binding<?>> getBindings() {
|
||||
return this.delegateInjector.getBindings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Binding<T> getBinding(Key<T> key) {
|
||||
return this.delegateInjector.getBinding(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Binding<T> getBinding(Class<T> type) {
|
||||
return this.delegateInjector.getBinding(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
|
||||
return this.delegateInjector.findBindingsByType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector getParent() {
|
||||
return delegateInjector.getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector createChildInjector(Iterable<? extends Module> modules) {
|
||||
return delegateInjector.createChildInjector(modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector createChildInjector(Module... modules) {
|
||||
return delegateInjector.createChildInjector(modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Provider<T> getProvider(Key<T> key) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Provider<T> getProvider(Class<T> type) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Key<T> key) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Class<T> type) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,6 @@ import static org.elasticsearch.common.inject.internal.Annotations.findScopeAnno
|
|||
*/
|
||||
class InjectorImpl implements Injector, Lookups {
|
||||
final State state;
|
||||
final InjectorImpl parent;
|
||||
boolean readOnly;
|
||||
BindingsMultimap bindingsMultimap = new BindingsMultimap();
|
||||
final Initializer initializer;
|
||||
|
@ -76,16 +75,10 @@ class InjectorImpl implements Injector, Lookups {
|
|||
|
||||
Lookups lookups = new DeferredLookups(this);
|
||||
|
||||
InjectorImpl(@Nullable InjectorImpl parent, State state, Initializer initializer) {
|
||||
this.parent = parent;
|
||||
InjectorImpl(State state, Initializer initializer) {
|
||||
this.state = state;
|
||||
this.initializer = initializer;
|
||||
|
||||
if (parent != null) {
|
||||
localContext = parent.localContext;
|
||||
} else {
|
||||
localContext = new ThreadLocal<>();
|
||||
}
|
||||
localContext = new ThreadLocal<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -106,21 +99,6 @@ class InjectorImpl implements Injector, Lookups {
|
|||
return bindingsMultimap.getAll(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding for {@code key}
|
||||
*/
|
||||
@Override
|
||||
public <T> BindingImpl<T> getBinding(Key<T> key) {
|
||||
Errors errors = new Errors(key);
|
||||
try {
|
||||
BindingImpl<T> result = getBindingOrThrow(key, errors);
|
||||
errors.throwConfigurationExceptionIfErrorsExist();
|
||||
return result;
|
||||
} catch (ErrorsException e) {
|
||||
throw new ConfigurationException(errors.merge(e.getErrors()).getMessages());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a binding implementation. First, it check to see if the parent has a binding. If the
|
||||
* parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
|
||||
|
@ -139,29 +117,6 @@ class InjectorImpl implements Injector, Lookups {
|
|||
return getJustInTimeBinding(key, errors);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Binding<T> getBinding(Class<T> type) {
|
||||
return getBinding(Key.get(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector createChildInjector(Iterable<? extends Module> modules) {
|
||||
return new InjectorBuilder()
|
||||
.parentInjector(this)
|
||||
.addModules(modules)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Injector createChildInjector(Module... modules) {
|
||||
return createChildInjector(Arrays.asList(modules));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a just-in-time binding for {@code key}, creating it if necessary.
|
||||
*
|
||||
|
@ -171,13 +126,11 @@ class InjectorImpl implements Injector, Lookups {
|
|||
throws ErrorsException {
|
||||
synchronized (state.lock()) {
|
||||
// first try to find a JIT binding that we've already created
|
||||
for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
|
||||
@SuppressWarnings("unchecked") // we only store bindings that match their key
|
||||
BindingImpl<T> binding = (BindingImpl<T>) injector.jitBindings.get(key);
|
||||
@SuppressWarnings("unchecked") // we only store bindings that match their key
|
||||
BindingImpl<T> binding = (BindingImpl<T>) jitBindings.get(key);
|
||||
|
||||
if (binding != null) {
|
||||
return binding;
|
||||
}
|
||||
if (binding != null) {
|
||||
return binding;
|
||||
}
|
||||
|
||||
return createJustInTimeBindingRecursive(key, errors);
|
||||
|
@ -600,14 +553,6 @@ class InjectorImpl implements Injector, Lookups {
|
|||
*/
|
||||
private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors)
|
||||
throws ErrorsException {
|
||||
// ask the parent to create the JIT binding
|
||||
if (parent != null && !parent.readOnly /* ES: don't check on parent if its read only, its already created all the bindings it can*/) {
|
||||
try {
|
||||
return parent.createJustInTimeBindingRecursive(key, new Errors());
|
||||
} catch (ErrorsException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
if (state.isBlacklisted(key)) {
|
||||
throw errors.childBindingAlreadySet(key).toException();
|
||||
}
|
||||
|
@ -686,12 +631,6 @@ class InjectorImpl implements Injector, Lookups {
|
|||
return getBindingOrThrow(key, errors).getInternalFactory();
|
||||
}
|
||||
|
||||
// not test-covered
|
||||
@Override
|
||||
public Map<Key<?>, Binding<?>> getBindings() {
|
||||
return state.getExplicitBindingsThisLevel();
|
||||
}
|
||||
|
||||
private static class BindingsMultimap {
|
||||
final Map<TypeLiteral<?>, List<Binding<?>>> multimap = new HashMap<>();
|
||||
|
||||
|
|
|
@ -50,18 +50,12 @@ class InjectorShell {
|
|||
|
||||
private final List<Element> elements;
|
||||
private final InjectorImpl injector;
|
||||
private final PrivateElements privateElements;
|
||||
|
||||
private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
|
||||
this.privateElements = builder.privateElements;
|
||||
private InjectorShell(List<Element> elements, InjectorImpl injector) {
|
||||
this.elements = elements;
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
PrivateElements getPrivateElements() {
|
||||
return privateElements;
|
||||
}
|
||||
|
||||
InjectorImpl getInjector() {
|
||||
return injector;
|
||||
}
|
||||
|
@ -134,7 +128,7 @@ class InjectorShell {
|
|||
throw new IllegalStateException("no state. Did you remember to lock() ?");
|
||||
}
|
||||
|
||||
InjectorImpl injector = new InjectorImpl(parent, state, initializer);
|
||||
InjectorImpl injector = new InjectorImpl(state, initializer);
|
||||
if (privateElements != null) {
|
||||
privateElements.initInjector(injector);
|
||||
}
|
||||
|
@ -167,7 +161,7 @@ class InjectorShell {
|
|||
stopwatch.resetAndLog("Binding creation");
|
||||
|
||||
List<InjectorShell> injectorShells = new ArrayList<>();
|
||||
injectorShells.add(new InjectorShell(this, elements, injector));
|
||||
injectorShells.add(new InjectorShell(elements, injector));
|
||||
|
||||
// recursively build child shells
|
||||
PrivateElementProcessor processor = new PrivateElementProcessor(errors, stage);
|
||||
|
|
|
@ -1,239 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch licenses this file to you 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 org.elasticsearch.common.inject;
|
||||
|
||||
import org.elasticsearch.common.inject.matcher.Matcher;
|
||||
import org.elasticsearch.common.inject.name.Names;
|
||||
import org.elasticsearch.common.inject.spi.Message;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class Injectors {
|
||||
|
||||
public static Throwable getFirstErrorFailure(CreationException e) {
|
||||
if (e.getErrorMessages().isEmpty()) {
|
||||
return e;
|
||||
}
|
||||
// return the first message that has root cause, probably an actual error
|
||||
for (Message message : e.getErrorMessages()) {
|
||||
if (message.getCause() != null) {
|
||||
return message.getCause();
|
||||
}
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the given type with the {@link org.elasticsearch.common.inject.name.Named}
|
||||
* annotation value.
|
||||
* <p>
|
||||
* This method allows you to switch this code
|
||||
* <code>injector.getInstance(Key.get(type, Names.named(name)));</code>
|
||||
* <p>
|
||||
* to the more concise
|
||||
* <code>Injectors.getInstance(injector, type, name);</code>
|
||||
*/
|
||||
public static <T> T getInstance(Injector injector, java.lang.Class<T> type, String name) {
|
||||
return injector.getInstance(Key.get(type, Names.named(name)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all instances of the given base type
|
||||
*
|
||||
* @param baseClass the base type of objects required
|
||||
* @param <T> the base type
|
||||
* @return a set of objects returned from this injector
|
||||
*/
|
||||
public static <T> Set<T> getInstancesOf(Injector injector, Class<T> baseClass) {
|
||||
Set<T> answer = new HashSet<>();
|
||||
Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings().entrySet();
|
||||
for (Entry<Key<?>, Binding<?>> entry : entries) {
|
||||
Key<?> key = entry.getKey();
|
||||
Class<?> keyType = getKeyType(key);
|
||||
if (keyType != null && baseClass.isAssignableFrom(keyType)) {
|
||||
Binding<?> binding = entry.getValue();
|
||||
Object value = binding.getProvider().get();
|
||||
if (value != null) {
|
||||
T castValue = baseClass.cast(value);
|
||||
answer.add(castValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all instances matching the given matcher
|
||||
*
|
||||
* @param matcher matches the types to return instances
|
||||
* @return a set of objects returned from this injector
|
||||
*/
|
||||
public static <T> Set<T> getInstancesOf(Injector injector, Matcher<Class> matcher) {
|
||||
Set<T> answer = new HashSet<>();
|
||||
Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings().entrySet();
|
||||
for (Entry<Key<?>, Binding<?>> entry : entries) {
|
||||
Key<?> key = entry.getKey();
|
||||
Class<?> keyType = getKeyType(key);
|
||||
if (keyType != null && matcher.matches(keyType)) {
|
||||
Binding<?> binding = entry.getValue();
|
||||
Object value = binding.getProvider().get();
|
||||
answer.add((T) value);
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all of the providers matching the given matcher
|
||||
*
|
||||
* @param matcher matches the types to return instances
|
||||
* @return a set of objects returned from this injector
|
||||
*/
|
||||
public static <T> Set<Provider<T>> getProvidersOf(Injector injector, Matcher<Class> matcher) {
|
||||
Set<Provider<T>> answer = new HashSet<>();
|
||||
Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings().entrySet();
|
||||
for (Entry<Key<?>, Binding<?>> entry : entries) {
|
||||
Key<?> key = entry.getKey();
|
||||
Class<?> keyType = getKeyType(key);
|
||||
if (keyType != null && matcher.matches(keyType)) {
|
||||
Binding<?> binding = entry.getValue();
|
||||
answer.add((Provider<T>) binding.getProvider());
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all providers of the given base type
|
||||
*
|
||||
* @param baseClass the base type of objects required
|
||||
* @param <T> the base type
|
||||
* @return a set of objects returned from this injector
|
||||
*/
|
||||
public static <T> Set<Provider<T>> getProvidersOf(Injector injector, Class<T> baseClass) {
|
||||
Set<Provider<T>> answer = new HashSet<>();
|
||||
Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings().entrySet();
|
||||
for (Entry<Key<?>, Binding<?>> entry : entries) {
|
||||
Key<?> key = entry.getKey();
|
||||
Class<?> keyType = getKeyType(key);
|
||||
if (keyType != null && baseClass.isAssignableFrom(keyType)) {
|
||||
Binding<?> binding = entry.getValue();
|
||||
answer.add((Provider<T>) binding.getProvider());
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a binding exists for the given matcher
|
||||
*/
|
||||
public static boolean hasBinding(Injector injector, Matcher<Class> matcher) {
|
||||
return !getBindingsOf(injector, matcher).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a binding exists for the given base class
|
||||
*/
|
||||
public static boolean hasBinding(Injector injector, Class<?> baseClass) {
|
||||
return !getBindingsOf(injector, baseClass).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a binding exists for the given key
|
||||
*/
|
||||
public static boolean hasBinding(Injector injector, Key<?> key) {
|
||||
Binding<?> binding = getBinding(injector, key);
|
||||
return binding != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binding for the given key or null if there is no such binding
|
||||
*/
|
||||
public static Binding<?> getBinding(Injector injector, Key<?> key) {
|
||||
Map<Key<?>, Binding<?>> bindings = injector.getBindings();
|
||||
Binding<?> binding = bindings.get(key);
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all of the bindings matching the given matcher
|
||||
*
|
||||
* @param matcher matches the types to return instances
|
||||
* @return a set of objects returned from this injector
|
||||
*/
|
||||
public static Set<Binding<?>> getBindingsOf(Injector injector, Matcher<Class> matcher) {
|
||||
Set<Binding<?>> answer = new HashSet<>();
|
||||
Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings().entrySet();
|
||||
for (Entry<Key<?>, Binding<?>> entry : entries) {
|
||||
Key<?> key = entry.getKey();
|
||||
Class<?> keyType = getKeyType(key);
|
||||
if (keyType != null && matcher.matches(keyType)) {
|
||||
answer.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of all bindings of the given base type
|
||||
*
|
||||
* @param baseClass the base type of objects required
|
||||
* @return a set of objects returned from this injector
|
||||
*/
|
||||
public static Set<Binding<?>> getBindingsOf(Injector injector, Class<?> baseClass) {
|
||||
Set<Binding<?>> answer = new HashSet<>();
|
||||
Set<Entry<Key<?>, Binding<?>>> entries = injector.getBindings().entrySet();
|
||||
for (Entry<Key<?>, Binding<?>> entry : entries) {
|
||||
Key<?> key = entry.getKey();
|
||||
Class<?> keyType = getKeyType(key);
|
||||
if (keyType != null && baseClass.isAssignableFrom(keyType)) {
|
||||
answer.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key type of the given key
|
||||
*/
|
||||
public static <T> Class<?> getKeyType(Key<?> key) {
|
||||
Class<?> keyType = null;
|
||||
TypeLiteral<?> typeLiteral = key.getTypeLiteral();
|
||||
Type type = typeLiteral.getType();
|
||||
if (type instanceof Class) {
|
||||
keyType = (Class<?>) type;
|
||||
}
|
||||
return keyType;
|
||||
}
|
||||
|
||||
public static void cleanCaches(Injector injector) {
|
||||
((InjectorImpl) injector).clearCache();
|
||||
if (injector.getParent() != null) {
|
||||
cleanCaches(injector.getParent());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,9 +23,6 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class ModulesBuilder implements Iterable<Module> {
|
||||
|
||||
private final List<Module> modules = new ArrayList<>();
|
||||
|
@ -44,19 +41,10 @@ public class ModulesBuilder implements Iterable<Module> {
|
|||
|
||||
public Injector createInjector() {
|
||||
Injector injector = Guice.createInjector(modules);
|
||||
Injectors.cleanCaches(injector);
|
||||
((InjectorImpl) injector).clearCache();
|
||||
// in ES, we always create all instances as if they are eager singletons
|
||||
// this allows for considerable memory savings (no need to store construction info) as well as cycles
|
||||
((InjectorImpl) injector).readOnlyAllSingletons();
|
||||
return injector;
|
||||
}
|
||||
|
||||
public Injector createChildInjector(Injector injector) {
|
||||
Injector childInjector = injector.createChildInjector(modules);
|
||||
Injectors.cleanCaches(childInjector);
|
||||
// in ES, we always create all instances as if they are eager singletons
|
||||
// this allows for considerable memory savings (no need to store construction info) as well as cycles
|
||||
((InjectorImpl) childInjector).readOnlyAllSingletons();
|
||||
return childInjector;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,10 +61,6 @@ import java.lang.annotation.Annotation;
|
|||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* Private modules are implemented using {@link Injector#createChildInjector(Module[]) parent
|
||||
* injectors}. When it can satisfy their dependencies, just-in-time bindings will be created in the
|
||||
* root environment. Such bindings are shared among all environments in the tree.
|
||||
* <p>
|
||||
* The scope of a binding is constrained to its environment. A singleton bound in a private
|
||||
* module will be unique to its environment. But a binding for the same type in a different private
|
||||
* module will yield a different instance.
|
||||
|
@ -143,13 +139,6 @@ public abstract class PrivateModule implements Module {
|
|||
return binder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#bindScope(Class, Scope)
|
||||
*/
|
||||
protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
|
||||
binder.bindScope(scopeAnnotation, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#bind(Key)
|
||||
*/
|
||||
|
@ -171,13 +160,6 @@ public abstract class PrivateModule implements Module {
|
|||
return binder.bind(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#bindConstant()
|
||||
*/
|
||||
protected final AnnotatedConstantBindingBuilder bindConstant() {
|
||||
return binder.bindConstant();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#install(Module)
|
||||
*/
|
||||
|
@ -206,34 +188,6 @@ public abstract class PrivateModule implements Module {
|
|||
binder.addError(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#requestInjection(Object)
|
||||
*/
|
||||
protected final void requestInjection(Object instance) {
|
||||
binder.requestInjection(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#requestStaticInjection(Class[])
|
||||
*/
|
||||
protected final void requestStaticInjection(Class<?>... types) {
|
||||
binder.requestStaticInjection(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs Guice to require a binding to the given key.
|
||||
*/
|
||||
protected final void requireBinding(Key<?> key) {
|
||||
binder.getProvider(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs Guice to require a binding to the given type.
|
||||
*/
|
||||
protected final void requireBinding(Class<?> type) {
|
||||
binder.getProvider(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#getProvider(Key)
|
||||
*/
|
||||
|
@ -248,21 +202,6 @@ public abstract class PrivateModule implements Module {
|
|||
return binder.getProvider(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#convertToTypes(org.elasticsearch.common.inject.matcher.Matcher, org.elasticsearch.common.inject.spi.TypeConverter)
|
||||
*/
|
||||
protected final void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
|
||||
TypeConverter converter) {
|
||||
binder.convertToTypes(typeMatcher, converter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#currentStage()
|
||||
*/
|
||||
protected final Stage currentStage() {
|
||||
return binder.currentStage();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#getMembersInjector(Class)
|
||||
*/
|
||||
|
@ -276,12 +215,4 @@ public abstract class PrivateModule implements Module {
|
|||
protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
|
||||
return binder.getMembersInjector(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Binder#bindListener(org.elasticsearch.common.inject.matcher.Matcher, org.elasticsearch.common.inject.spi.TypeListener)
|
||||
*/
|
||||
protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
|
||||
TypeListener listener) {
|
||||
binder.bindListener(typeMatcher, listener);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ public class FactoryProvider<F> implements Provider<F>, HasDependencies {
|
|||
|
||||
/*
|
||||
* This class implements the old @AssistedInject implementation that manually matches constructors
|
||||
* to factory methods. The new child injector implementation lives in FactoryProvider2.
|
||||
* to factory methods.
|
||||
*/
|
||||
|
||||
private Injector injector;
|
||||
|
@ -142,23 +142,6 @@ public class FactoryProvider<F> implements Provider<F>, HasDependencies {
|
|||
private final TypeLiteral<F> factoryType;
|
||||
private final Map<Method, AssistedConstructor<?>> factoryMethodToConstructor;
|
||||
|
||||
public static <F> Provider<F> newFactory(
|
||||
Class<F> factoryType, Class<?> implementationType) {
|
||||
return newFactory(TypeLiteral.get(factoryType), TypeLiteral.get(implementationType));
|
||||
}
|
||||
|
||||
public static <F> Provider<F> newFactory(
|
||||
TypeLiteral<F> factoryType, TypeLiteral<?> implementationType) {
|
||||
Map<Method, AssistedConstructor<?>> factoryMethodToConstructor
|
||||
= createMethodMapping(factoryType, implementationType);
|
||||
|
||||
if (!factoryMethodToConstructor.isEmpty()) {
|
||||
return new FactoryProvider<>(factoryType, factoryMethodToConstructor);
|
||||
} else {
|
||||
return new FactoryProvider2<>(factoryType, Key.get(implementationType));
|
||||
}
|
||||
}
|
||||
|
||||
private FactoryProvider(TypeLiteral<F> factoryType,
|
||||
Map<Method, AssistedConstructor<?>> factoryMethodToConstructor) {
|
||||
this.factoryType = factoryType;
|
||||
|
@ -166,22 +149,6 @@ public class FactoryProvider<F> implements Provider<F>, HasDependencies {
|
|||
checkDeclaredExceptionsMatch();
|
||||
}
|
||||
|
||||
@Inject
|
||||
void setInjectorAndCheckUnboundParametersAreInjectable(Injector injector) {
|
||||
this.injector = injector;
|
||||
for (AssistedConstructor<?> c : factoryMethodToConstructor.values()) {
|
||||
for (Parameter p : c.getAllParameters()) {
|
||||
if (!p.isProvidedByFactory() && !paramCanBeInjected(p, injector)) {
|
||||
// this is lame - we're not using the proper mechanism to add an
|
||||
// error to the injector. Throughout this class we throw exceptions
|
||||
// to add errors, which isn't really the best way in Guice
|
||||
throw newConfigurationException("Parameter of type '%s' is not injectable or annotated "
|
||||
+ "with @Assisted for Constructor '%s'", p, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDeclaredExceptionsMatch() {
|
||||
for (Map.Entry<Method, AssistedConstructor<?>> entry : factoryMethodToConstructor.entrySet()) {
|
||||
for (Class<?> constructorException : entry.getValue().getDeclaredExceptions()) {
|
||||
|
@ -204,82 +171,6 @@ public class FactoryProvider<F> implements Provider<F>, HasDependencies {
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean paramCanBeInjected(Parameter parameter, Injector injector) {
|
||||
return parameter.isBound(injector);
|
||||
}
|
||||
|
||||
private static Map<Method, AssistedConstructor<?>> createMethodMapping(
|
||||
TypeLiteral<?> factoryType, TypeLiteral<?> implementationType) {
|
||||
List<AssistedConstructor<?>> constructors = new ArrayList<>();
|
||||
|
||||
for (Constructor<?> constructor : implementationType.getRawType().getConstructors()) {
|
||||
if (constructor.getAnnotation(AssistedInject.class) != null) {
|
||||
@SuppressWarnings("unchecked") // the constructor type and implementation type agree
|
||||
AssistedConstructor assistedConstructor = new AssistedConstructor(
|
||||
constructor, implementationType.getParameterTypes(constructor));
|
||||
constructors.add(assistedConstructor);
|
||||
}
|
||||
}
|
||||
|
||||
if (constructors.isEmpty()) {
|
||||
return emptyMap();
|
||||
}
|
||||
|
||||
Method[] factoryMethods = factoryType.getRawType().getMethods();
|
||||
|
||||
if (constructors.size() != factoryMethods.length) {
|
||||
throw newConfigurationException("Constructor mismatch: %s has %s @AssistedInject "
|
||||
+ "constructors, factory %s has %s creation methods", implementationType,
|
||||
constructors.size(), factoryType, factoryMethods.length);
|
||||
}
|
||||
|
||||
Map<ParameterListKey, AssistedConstructor> paramsToConstructor = new HashMap<>();
|
||||
|
||||
for (AssistedConstructor c : constructors) {
|
||||
if (paramsToConstructor.containsKey(c.getAssistedParameters())) {
|
||||
throw new RuntimeException("Duplicate constructor, " + c);
|
||||
}
|
||||
paramsToConstructor.put(c.getAssistedParameters(), c);
|
||||
}
|
||||
|
||||
Map<Method, AssistedConstructor<?>> result = new HashMap<>();
|
||||
for (Method method : factoryMethods) {
|
||||
if (!method.getReturnType().isAssignableFrom(implementationType.getRawType())) {
|
||||
throw newConfigurationException("Return type of method %s is not assignable from %s",
|
||||
method, implementationType);
|
||||
}
|
||||
|
||||
List<Type> parameterTypes = new ArrayList<>();
|
||||
for (TypeLiteral<?> parameterType : factoryType.getParameterTypes(method)) {
|
||||
parameterTypes.add(parameterType.getType());
|
||||
}
|
||||
ParameterListKey methodParams = new ParameterListKey(parameterTypes);
|
||||
|
||||
if (!paramsToConstructor.containsKey(methodParams)) {
|
||||
throw newConfigurationException("%s has no @AssistInject constructor that takes the "
|
||||
+ "@Assisted parameters %s in that order. @AssistInject constructors are %s",
|
||||
implementationType, methodParams, paramsToConstructor.values());
|
||||
}
|
||||
|
||||
method.getParameterAnnotations();
|
||||
for (Annotation[] parameterAnnotations : method.getParameterAnnotations()) {
|
||||
for (Annotation parameterAnnotation : parameterAnnotations) {
|
||||
if (parameterAnnotation.annotationType() == Assisted.class) {
|
||||
throw newConfigurationException("Factory method %s has an @Assisted parameter, which "
|
||||
+ "is incompatible with the deprecated @AssistedInject annotation. Please replace "
|
||||
+ "@AssistedInject with @Inject on the %s constructor.",
|
||||
method, implementationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AssistedConstructor matchingConstructor = paramsToConstructor.remove(methodParams);
|
||||
|
||||
result.put(method, matchingConstructor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Dependency<?>> getDependencies() {
|
||||
Set<Dependency<?>> dependencies = new HashSet<>();
|
||||
|
|
|
@ -1,283 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* 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 org.elasticsearch.common.inject.assistedinject;
|
||||
|
||||
import org.elasticsearch.common.inject.AbstractModule;
|
||||
import org.elasticsearch.common.inject.Binder;
|
||||
import org.elasticsearch.common.inject.Binding;
|
||||
import org.elasticsearch.common.inject.ConfigurationException;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.inject.Injector;
|
||||
import org.elasticsearch.common.inject.Key;
|
||||
import org.elasticsearch.common.inject.Module;
|
||||
import org.elasticsearch.common.inject.Provider;
|
||||
import org.elasticsearch.common.inject.ProvisionException;
|
||||
import org.elasticsearch.common.inject.TypeLiteral;
|
||||
import org.elasticsearch.common.inject.internal.Errors;
|
||||
import org.elasticsearch.common.inject.internal.ErrorsException;
|
||||
import org.elasticsearch.common.inject.spi.Message;
|
||||
import org.elasticsearch.common.inject.util.Providers;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
import static org.elasticsearch.common.inject.internal.Annotations.getKey;
|
||||
|
||||
/**
|
||||
* The newer implementation of factory provider. This implementation uses a child injector to
|
||||
* create values.
|
||||
*
|
||||
* @author jessewilson@google.com (Jesse Wilson)
|
||||
* @author dtm@google.com (Daniel Martin)
|
||||
*/
|
||||
public final class FactoryProvider2<F> implements InvocationHandler, Provider<F> {
|
||||
|
||||
/**
|
||||
* if a factory method parameter isn't annotated, it gets this annotation.
|
||||
*/
|
||||
static final Assisted DEFAULT_ANNOTATION = new Assisted() {
|
||||
@Override
|
||||
public String value() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Annotation> annotationType() {
|
||||
return Assisted.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o instanceof Assisted
|
||||
&& ((Assisted) o).value().equals("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 127 * "value".hashCode() ^ "".hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "@" + Assisted.class.getName() + "(value=)";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* the produced type, or null if all methods return concrete types
|
||||
*/
|
||||
private final Key<?> producedType;
|
||||
private final Map<Method, Key<?>> returnTypesByMethod;
|
||||
private final Map<Method, List<Key<?>>> paramTypes;
|
||||
|
||||
/**
|
||||
* the hosting injector, or null if we haven't been initialized yet
|
||||
*/
|
||||
private Injector injector;
|
||||
|
||||
/**
|
||||
* the factory interface, implemented and provided
|
||||
*/
|
||||
private final F factory;
|
||||
|
||||
/**
|
||||
* @param factoryType a Java interface that defines one or more create methods.
|
||||
* @param producedType a concrete type that is assignable to the return types of all factory
|
||||
* methods.
|
||||
*/
|
||||
FactoryProvider2(TypeLiteral<F> factoryType, Key<?> producedType) {
|
||||
this.producedType = producedType;
|
||||
|
||||
Errors errors = new Errors();
|
||||
|
||||
@SuppressWarnings("unchecked") // we imprecisely treat the class literal of T as a Class<T>
|
||||
Class<F> factoryRawType = (Class) factoryType.getRawType();
|
||||
|
||||
try {
|
||||
Map<Method, Key<?>> returnTypesBuilder = new HashMap<>();
|
||||
Map<Method, List<Key<?>>> paramTypesBuilder = new HashMap<>();
|
||||
// TODO: also grab methods from superinterfaces
|
||||
for (Method method : factoryRawType.getMethods()) {
|
||||
Key<?> returnType = getKey(
|
||||
factoryType.getReturnType(method), method, method.getAnnotations(), errors);
|
||||
returnTypesBuilder.put(method, returnType);
|
||||
List<TypeLiteral<?>> params = factoryType.getParameterTypes(method);
|
||||
Annotation[][] paramAnnotations = method.getParameterAnnotations();
|
||||
int p = 0;
|
||||
List<Key<?>> keys = new ArrayList<>();
|
||||
for (TypeLiteral<?> param : params) {
|
||||
Key<?> paramKey = getKey(param, method, paramAnnotations[p++], errors);
|
||||
keys.add(assistKey(method, paramKey, errors));
|
||||
}
|
||||
paramTypesBuilder.put(method, Collections.unmodifiableList(keys));
|
||||
}
|
||||
returnTypesByMethod = unmodifiableMap(returnTypesBuilder);
|
||||
paramTypes = unmodifiableMap(paramTypesBuilder);
|
||||
} catch (ErrorsException e) {
|
||||
throw new ConfigurationException(e.getErrors().getMessages());
|
||||
}
|
||||
|
||||
factory = factoryRawType.cast(Proxy.newProxyInstance(factoryRawType.getClassLoader(),
|
||||
new Class[]{factoryRawType}, this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public F get() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key similar to {@code key}, but with an {@literal @}Assisted binding annotation.
|
||||
* This fails if another binding annotation is clobbered in the process. If the key already has
|
||||
* the {@literal @}Assisted annotation, it is returned as-is to preserve any String value.
|
||||
*/
|
||||
private <T> Key<T> assistKey(Method method, Key<T> key, Errors errors) throws ErrorsException {
|
||||
if (key.getAnnotationType() == null) {
|
||||
return Key.get(key.getTypeLiteral(), DEFAULT_ANNOTATION);
|
||||
} else if (key.getAnnotationType() == Assisted.class) {
|
||||
return key;
|
||||
} else {
|
||||
errors.withSource(method).addMessage(
|
||||
"Only @Assisted is allowed for factory parameters, but found @%s",
|
||||
key.getAnnotationType());
|
||||
throw errors.toException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At injector-creation time, we initialize the invocation handler. At this time we make sure
|
||||
* all factory methods will be able to build the target types.
|
||||
*/
|
||||
@Inject
|
||||
public void initialize(Injector injector) {
|
||||
if (this.injector != null) {
|
||||
throw new ConfigurationException(Collections.singletonList(new Message(FactoryProvider2.class,
|
||||
"Factories.create() factories may only be used in one Injector!")));
|
||||
}
|
||||
|
||||
this.injector = injector;
|
||||
|
||||
for (Method method : returnTypesByMethod.keySet()) {
|
||||
Object[] args = new Object[method.getParameterTypes().length];
|
||||
Arrays.fill(args, "dummy object for validating Factories");
|
||||
getBindingFromNewInjector(method, args); // throws if the binding isn't properly configured
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a child injector that binds the args, and returns the binding for the method's result.
|
||||
*/
|
||||
public Binding<?> getBindingFromNewInjector(final Method method, final Object[] args) {
|
||||
if (injector == null) {
|
||||
throw new IllegalStateException("Factories.create() factories cannot be used until they're initialized by Guice.");
|
||||
}
|
||||
|
||||
final Key<?> returnType = returnTypesByMethod.get(method);
|
||||
|
||||
Module assistedModule = new AbstractModule() {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked") // raw keys are necessary for the args array and return value
|
||||
protected void configure() {
|
||||
Binder binder = binder().withSource(method);
|
||||
|
||||
int p = 0;
|
||||
for (Key<?> paramKey : paramTypes.get(method)) {
|
||||
// Wrap in a Provider to cover null, and to prevent Guice from injecting the parameter
|
||||
binder.bind((Key) paramKey).toProvider(Providers.of(args[p++]));
|
||||
}
|
||||
|
||||
if (producedType != null && !returnType.equals(producedType)) {
|
||||
binder.bind(returnType).to((Key) producedType);
|
||||
} else {
|
||||
binder.bind(returnType);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Injector forCreate = injector.createChildInjector(assistedModule);
|
||||
return forCreate.getBinding(returnType);
|
||||
}
|
||||
|
||||
/**
|
||||
* When a factory method is invoked, we create a child injector that binds all parameters, then
|
||||
* use that to get an instance of the return type.
|
||||
*/
|
||||
@Override
|
||||
public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable {
|
||||
if (method.getDeclaringClass() == Object.class) {
|
||||
return method.invoke(this, args);
|
||||
}
|
||||
|
||||
Provider<?> provider = getBindingFromNewInjector(method, args).getProvider();
|
||||
try {
|
||||
return provider.get();
|
||||
} catch (ProvisionException e) {
|
||||
// if this is an exception declared by the factory method, throw it as-is
|
||||
if (e.getErrorMessages().size() == 1) {
|
||||
Message onlyError = e.getErrorMessages().iterator().next();
|
||||
Throwable cause = onlyError.getCause();
|
||||
if (cause != null && canRethrow(method, cause)) {
|
||||
throw cause;
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return factory.getClass().getInterfaces()[0].getName()
|
||||
+ " for " + producedType.getTypeLiteral();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o == this || o == factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// This way both this and its factory hash to the same spot, making hashCode consistent.
|
||||
return factory.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if {@code thrown} can be thrown by {@code invoked} without wrapping.
|
||||
*/
|
||||
static boolean canRethrow(Method invoked, Throwable thrown) {
|
||||
if (thrown instanceof Error || thrown instanceof RuntimeException) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (Class<?> declared : invoked.getExceptionTypes()) {
|
||||
if (declared.isInstance(thrown)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -87,34 +87,6 @@ class Parameter {
|
|||
: injector.getInstance(getPrimaryBindingKey());
|
||||
}
|
||||
|
||||
public boolean isBound(Injector injector) {
|
||||
return isBound(injector, getPrimaryBindingKey())
|
||||
|| isBound(injector, fixAnnotations(getPrimaryBindingKey()));
|
||||
}
|
||||
|
||||
private boolean isBound(Injector injector, Key<?> key) {
|
||||
// This method is particularly lame - we really need an API that can test
|
||||
// for any binding, implicit or explicit
|
||||
try {
|
||||
return injector.getBinding(key) != null;
|
||||
} catch (ConfigurationException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace annotation instances with annotation types, this is only
|
||||
* appropriate for testing if a key is bound and not for injecting.
|
||||
* <p>
|
||||
* See Guice bug 125,
|
||||
* http://code.google.com/p/google-guice/issues/detail?id=125
|
||||
*/
|
||||
public Key<?> fixAnnotations(Key<?> key) {
|
||||
return key.getAnnotation() == null
|
||||
? key
|
||||
: Key.get(key.getTypeLiteral(), key.getAnnotation().annotationType());
|
||||
}
|
||||
|
||||
Key<?> getPrimaryBindingKey() {
|
||||
return isProvider
|
||||
? getBindingForType(getProvidedType(type))
|
||||
|
|
|
@ -36,8 +36,7 @@ public interface ConvertedConstantBinding<T> extends Binding<T>, HasDependencies
|
|||
T getValue();
|
||||
|
||||
/**
|
||||
* Returns the key for the source binding. That binding can e retrieved from an injector using
|
||||
* {@link org.elasticsearch.common.inject.Injector#getBinding(Key) Injector.getBinding(key)}.
|
||||
* Returns the key for the source binding.
|
||||
*/
|
||||
Key<String> getSourceKey();
|
||||
|
||||
|
|
|
@ -25,9 +25,6 @@ import org.elasticsearch.common.inject.Binder;
|
|||
* Elements#getElements(org.elasticsearch.common.inject.Module[]) Elements.getElements()} to read the elements
|
||||
* from a module, and {@link Elements#getModule(Iterable) Elements.getModule()} to rewrite them.
|
||||
* This can be used for static analysis and generation of Guice modules.
|
||||
* <p>
|
||||
* The elements of an injector can be inspected and exercised. Use {@link
|
||||
* org.elasticsearch.common.inject.Injector#getBindings Injector.getBindings()} to reflect on Guice injectors.
|
||||
*
|
||||
* @author jessewilson@google.com (Jesse Wilson)
|
||||
* @author crazybob@google.com (Bob Lee)
|
||||
|
|
|
@ -80,13 +80,6 @@ public final class Elements {
|
|||
return getElements(Stage.DEVELOPMENT, Arrays.asList(modules));
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the elements executed by {@code modules}.
|
||||
*/
|
||||
public static List<Element> getElements(Stage stage, Module... modules) {
|
||||
return getElements(stage, Arrays.asList(modules));
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the elements executed by {@code modules}.
|
||||
*/
|
||||
|
@ -119,11 +112,6 @@ public final class Elements {
|
|||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> BindingTargetVisitor<T, T> getInstanceVisitor() {
|
||||
return (BindingTargetVisitor<T, T>) GET_INSTANCE_VISITOR;
|
||||
}
|
||||
|
||||
private static class RecordingBinder implements Binder, PrivateBinder {
|
||||
private final Stage stage;
|
||||
private final Set<Module> modules;
|
||||
|
|
|
@ -28,8 +28,7 @@ import org.elasticsearch.common.inject.Key;
|
|||
public interface LinkedKeyBinding<T> extends Binding<T> {
|
||||
|
||||
/**
|
||||
* Returns the linked key used to resolve injections. That binding can be retrieved from an
|
||||
* injector using {@link org.elasticsearch.common.inject.Injector#getBinding(Key) Injector.getBinding(key)}.
|
||||
* Returns the linked key used to resolve injections.
|
||||
*/
|
||||
Key<? extends T> getLinkedKey();
|
||||
|
||||
|
|
|
@ -30,9 +30,7 @@ import org.elasticsearch.common.inject.Provider;
|
|||
public interface ProviderBinding<T extends Provider<?>> extends Binding<T> {
|
||||
|
||||
/**
|
||||
* Returns the key whose binding is used to {@link Provider#get provide instances}. That binding
|
||||
* can be retrieved from an injector using {@link org.elasticsearch.common.inject.Injector#getBinding(Key)
|
||||
* Injector.getBinding(providedKey)}
|
||||
* Returns the key whose binding is used to {@link Provider#get provide instances}.
|
||||
*/
|
||||
Key<?> getProvidedKey();
|
||||
}
|
|
@ -30,9 +30,7 @@ import org.elasticsearch.common.inject.Provider;
|
|||
public interface ProviderKeyBinding<T> extends Binding<T> {
|
||||
|
||||
/**
|
||||
* Returns the key used to resolve the provider's binding. That binding can be retrieved from an
|
||||
* injector using {@link org.elasticsearch.common.inject.Injector#getBinding(Key)
|
||||
* Injector.getBinding(providerKey)}
|
||||
* Returns the key used to resolve the provider's binding.
|
||||
*/
|
||||
Key<? extends Provider<? extends T>> getProviderKey();
|
||||
|
||||
|
|
Loading…
Reference in New Issue