Merge pull request #19346 from rjernst/deguice_guice
Remove child injectors from guice
This commit is contained in:
commit
03bd152a01
|
@ -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