Created
July 7, 2014 19:14
-
-
Save gissuebot/cdd1cee33023f9ede4fe to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 778, comment 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: test/com/google/inject/commands/CommandRecorderTest.java | |
=================================================================== | |
--- test/com/google/inject/commands/CommandRecorderTest.java (revision 486) | |
+++ test/com/google/inject/commands/CommandRecorderTest.java (working copy) | |
@@ -760,6 +760,10 @@ | |
public Void visitGetProvider(GetProviderCommand command) { | |
throw new AssertionFailedError(); | |
} | |
+ | |
+ public Void visitAddBindingFactory(AddBindingFactoryCommand command) { | |
+ throw new AssertionFailedError(); | |
+ } | |
} | |
@Retention(RUNTIME) | |
Index: src/com/google/inject/matcher/Matchers.java | |
=================================================================== | |
--- src/com/google/inject/matcher/Matchers.java (revision 491) | |
+++ src/com/google/inject/matcher/Matchers.java (working copy) | |
@@ -17,12 +17,15 @@ | |
package com.google.inject.matcher; | |
import com.google.inject.internal.Objects; | |
+import com.google.inject.spi.Dependency; | |
import java.io.Serializable; | |
import java.lang.annotation.Annotation; | |
import java.lang.annotation.Retention; | |
import java.lang.annotation.RetentionPolicy; | |
import java.lang.reflect.AnnotatedElement; | |
+import java.lang.reflect.Constructor; | |
+import java.lang.reflect.Member; | |
import java.lang.reflect.Method; | |
/** | |
@@ -340,4 +343,111 @@ | |
return "returns(" + returnType + ")"; | |
} | |
} | |
+ | |
+ /** | |
+ * Helper class to allow matching of annotations decoupled from their element | |
+ */ | |
+ private static final class AnnotationBucket implements AnnotatedElement { | |
+ private final Annotation[] annotations; | |
+ public AnnotationBucket(Annotation... annotations) { | |
+ this.annotations = annotations; | |
+ } | |
+ public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { | |
+ for (Annotation a : annotations) { | |
+ if (annotationClass.isInstance(a)) { | |
+ return annotationClass.cast(a); | |
+ } | |
+ } | |
+ return null; | |
+ } | |
+ public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { | |
+ return getAnnotation(annotationClass) != null; | |
+ } | |
+ public Annotation[] getAnnotations() { | |
+ return annotations; | |
+ } | |
+ public Annotation[] getDeclaredAnnotations() { | |
+ return annotations; | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns a matcher which matches dependencies with matching key annotations. | |
+ */ | |
+ public static Matcher<Dependency<?>> key( | |
+ Matcher<AnnotatedElement> keyAnnotation) { | |
+ return new DependencyKey(keyAnnotation); | |
+ } | |
+ | |
+ private static final class DependencyKey extends | |
+ AbstractMatcher<Dependency<?>> implements Serializable { | |
+ private final Matcher<AnnotatedElement> keyAnnotation; | |
+ | |
+ public DependencyKey(Matcher<AnnotatedElement> keyAnnotation) { | |
+ this.keyAnnotation = Objects.nonNull(keyAnnotation, "key annotation matcher"); | |
+ } | |
+ | |
+ public boolean matches(Dependency<?> d) { | |
+ return keyAnnotation.matches(new AnnotationBucket(d.getKey().getAnnotation())); | |
+ } | |
+ | |
+ @Override public boolean equals(Object other) { | |
+ return other instanceof DependencyKey | |
+ && ((DependencyKey) other).keyAnnotation.equals(keyAnnotation); | |
+ } | |
+ | |
+ @Override public int hashCode() { | |
+ return 37 * keyAnnotation.hashCode(); | |
+ } | |
+ | |
+ @Override public String toString() { | |
+ return "key(" + keyAnnotation + ")"; | |
+ } | |
+ } | |
+ | |
+ /** | |
+ * Returns a matcher which matches dependencies with matching member annotations. | |
+ */ | |
+ public static Matcher<Dependency<?>> member( | |
+ Matcher<AnnotatedElement> memberAnnotation) { | |
+ return new DependencyMember(memberAnnotation); | |
+ } | |
+ | |
+ private static final class DependencyMember extends | |
+ AbstractMatcher<Dependency<?>> implements Serializable { | |
+ private final Matcher<AnnotatedElement> memberAnnotation; | |
+ | |
+ public DependencyMember(Matcher<AnnotatedElement> memberAnnotation) { | |
+ this.memberAnnotation = Objects.nonNull(memberAnnotation, "member annotation matcher"); | |
+ } | |
+ | |
+ public boolean matches(Dependency<?> d) { | |
+ Member m = d.getMember(); | |
+ int i = d.getParameterIndex(); | |
+ Annotation[] as = new Annotation[0]; | |
+ | |
+ if (i < 0) { | |
+ as = ((AnnotatedElement)m).getAnnotations(); | |
+ } else if (m instanceof Constructor) { | |
+ as = ((Constructor<?>)m).getParameterAnnotations()[i]; | |
+ } else if (m instanceof Method) { | |
+ as = ((Method)m).getParameterAnnotations()[i]; | |
+ } | |
+ | |
+ return memberAnnotation.matches(new AnnotationBucket(as)); | |
+ } | |
+ | |
+ @Override public boolean equals(Object other) { | |
+ return other instanceof DependencyMember | |
+ && ((DependencyMember) other).memberAnnotation.equals(memberAnnotation); | |
+ } | |
+ | |
+ @Override public int hashCode() { | |
+ return 37 * memberAnnotation.hashCode(); | |
+ } | |
+ | |
+ @Override public String toString() { | |
+ return "member(" + memberAnnotation + ")"; | |
+ } | |
+ } | |
} | |
\ No newline at end of file | |
Index: src/com/google/inject/Binder.java | |
=================================================================== | |
--- src/com/google/inject/Binder.java (revision 486) | |
+++ src/com/google/inject/Binder.java (working copy) | |
@@ -20,6 +20,7 @@ | |
import com.google.inject.binder.AnnotatedConstantBindingBuilder; | |
import com.google.inject.binder.LinkedBindingBuilder; | |
import com.google.inject.matcher.Matcher; | |
+import com.google.inject.spi.Dependency; | |
import com.google.inject.spi.Message; | |
import com.google.inject.spi.TypeConverter; | |
import java.lang.annotation.Annotation; | |
@@ -284,4 +285,15 @@ | |
*/ | |
void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, | |
TypeConverter converter); | |
+ | |
+ /** | |
+ * Adds a binding factory to provide missing dependencies matched by a matcher. | |
+ * | |
+ * @param dependencyMatcher matches missing dependencies the binding factory | |
+ * should attempt to satisfy. For example: {@code any()}. | |
+ * @param bindingFactory factory that can produce bindings on request | |
+ */ | |
+ <T> void addBindingFactory( | |
+ Matcher<? super Dependency<? extends T>> dependencyMatcher, | |
+ BindingFactory<T> bindingFactory); | |
} | |
Index: src/com/google/inject/internal/ResolvingCallable.java | |
=================================================================== | |
--- src/com/google/inject/internal/ResolvingCallable.java (revision 486) | |
+++ src/com/google/inject/internal/ResolvingCallable.java (working copy) | |
@@ -29,9 +29,22 @@ | |
*/ | |
public abstract class ResolvingCallable<T> implements Callable<T> { | |
public abstract T call() throws ResolveFailedException; | |
+ public boolean retry() {return false;} | |
public T runWithDefaultSource(Object source) throws ResolveFailedException { | |
try { | |
+ return run(source); | |
+ } catch (ResolveFailedException e) { | |
+ if (retry()) { | |
+ return run(source); | |
+ } else { | |
+ throw e; | |
+ } | |
+ } | |
+ } | |
+ | |
+ private T run(Object source) throws ResolveFailedException { | |
+ try { | |
return SourceProviders.withDefaultChecked(source, this); | |
} catch (ResolveFailedException e) { | |
throw e; | |
Index: src/com/google/inject/InjectorImpl.java | |
=================================================================== | |
--- src/com/google/inject/InjectorImpl.java (revision 486) | |
+++ src/com/google/inject/InjectorImpl.java (working copy) | |
@@ -78,6 +78,8 @@ | |
final ErrorHandler errorHandler; | |
Reflection reflection; | |
+ MissingDependencyHandler missingDependencyHandler; | |
+ | |
InjectorImpl(Injector parentInjector, ErrorHandler errorHandler) { | |
this.parentInjector = parentInjector; | |
this.errorHandler = errorHandler; | |
@@ -155,6 +157,10 @@ | |
SourceProviders.withDefault(defaultSource, runnable); | |
} | |
+ void setMissingDependencyHandler(MissingDependencyHandler dependencyHandler) { | |
+ this.missingDependencyHandler = dependencyHandler; | |
+ } | |
+ | |
/** | |
* Returns the binding for {@code key}, or {@code null} if that binding | |
* cannot be resolved. | |
@@ -854,14 +860,20 @@ | |
final Key<?> key = Keys.get( | |
field.getGenericType(), field, field.getAnnotations(), errorHandler); | |
+ | |
+ this.injectionPoint = InjectionPoint.newInstance(field, | |
+ Nullability.forAnnotations(field.getAnnotations()), key, injector); | |
+ | |
+ final MissingDependencyHandler handler = missingDependencyHandler; | |
+ | |
factory = new ResolvingCallable<InternalFactory<?>>() { | |
public InternalFactory<?> call() throws ResolveFailedException { | |
return injector.getInternalFactory(key); | |
} | |
+ public boolean retry() { | |
+ return null == handler ? false : handler.handle(injectionPoint); | |
+ } | |
}.runWithDefaultSource(StackTraceElements.forMember(field)); | |
- | |
- this.injectionPoint = InjectionPoint.newInstance(field, | |
- Nullability.forAnnotations(field.getAnnotations()), key, injector); | |
} | |
public Collection<Dependency<?>> getDependencies() { | |
@@ -916,15 +928,22 @@ | |
<T> SingleParameterInjector<T> createParameterInjector( | |
final Parameter<T> parameter, Member member) | |
throws ResolveFailedException { | |
+ | |
+ final InjectionPoint<T> injectionPoint = InjectionPoint.newInstance( | |
+ member, parameter.getIndex(), parameter.getNullability(), parameter.getKey(), this); | |
+ | |
+ final MissingDependencyHandler handler = missingDependencyHandler; | |
+ | |
InternalFactory<? extends T> factory | |
= new ResolvingCallable<InternalFactory<? extends T>>() { | |
public InternalFactory<? extends T> call() throws ResolveFailedException { | |
return getInternalFactory(parameter.getKey()); | |
} | |
+ public boolean retry() { | |
+ return null == handler ? false : handler.handle(injectionPoint); | |
+ } | |
}.runWithDefaultSource(StackTraceElements.forMember(member)); | |
- InjectionPoint<T> injectionPoint = InjectionPoint.newInstance( | |
- member, parameter.getIndex(), parameter.getNullability(), parameter.getKey(), this); | |
return new SingleParameterInjector<T>(injectionPoint, factory); | |
} | |
Index: src/com/google/inject/commands/CommandRecorder.java | |
=================================================================== | |
--- src/com/google/inject/commands/CommandRecorder.java (revision 486) | |
+++ src/com/google/inject/commands/CommandRecorder.java (working copy) | |
@@ -22,6 +22,8 @@ | |
import com.google.inject.matcher.Matcher; | |
import com.google.inject.spi.SourceProviders; | |
import static com.google.inject.spi.SourceProviders.defaultSource; | |
+import com.google.inject.internal.ErrorHandler; | |
+import com.google.inject.spi.Dependency; | |
import com.google.inject.spi.TypeConverter; | |
import org.aopalliance.intercept.MethodInterceptor; | |
@@ -115,10 +117,19 @@ | |
commands.add(new AddThrowableErrorCommand(defaultSource(), t)); | |
} | |
+ private final class BindingErrorHandler implements ErrorHandler { | |
+ public void handle(Object source, String message) { | |
+ commands.add(new AddMessageErrorCommand(source, message, new Object[0])); | |
+ } | |
+ public void handle(Object source, String message, Object... arguments) { | |
+ commands.add(new AddMessageErrorCommand(source, message, arguments)); | |
+ } | |
+ } | |
+ | |
public <T> BindCommand<T>.BindingBuilder bind(Key<T> key) { | |
BindCommand<T> bindCommand = new BindCommand<T>(defaultSource(), key); | |
commands.add(bindCommand); | |
- return bindCommand.bindingBuilder(RecordingBinder.this); | |
+ return bindCommand.bindingBuilder(new BindingErrorHandler()); | |
} | |
public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) { | |
@@ -132,7 +143,7 @@ | |
public AnnotatedConstantBindingBuilder bindConstant() { | |
BindConstantCommand bindConstantCommand = new BindConstantCommand(defaultSource()); | |
commands.add(bindConstantCommand); | |
- return bindConstantCommand.bindingBuilder(RecordingBinder.this); | |
+ return bindConstantCommand.bindingBuilder(new BindingErrorHandler()); | |
} | |
public <T> Provider<T> getProvider(final Key<T> key) { | |
@@ -157,6 +168,13 @@ | |
commands.add(new ConvertToTypesCommand(defaultSource(), typeMatcher, converter)); | |
} | |
+ public <T> void addBindingFactory( | |
+ Matcher<? super Dependency<? extends T>> dependencyMatcher, | |
+ BindingFactory<T> bindingFactory) { | |
+ commands.add(new AddBindingFactoryCommand<T>( | |
+ defaultSource(), dependencyMatcher, bindingFactory)); | |
+ } | |
+ | |
@Override public String toString() { | |
return "Binder"; | |
} | |
Index: src/com/google/inject/commands/AddBindingFactoryCommand.java | |
=================================================================== | |
--- src/com/google/inject/commands/AddBindingFactoryCommand.java (revision 0) | |
+++ src/com/google/inject/commands/AddBindingFactoryCommand.java (revision 0) | |
@@ -0,0 +1,58 @@ | |
+/** | |
+ * 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 com.google.inject.commands; | |
+ | |
+import com.google.inject.BindingFactory; | |
+import static com.google.inject.internal.Objects.nonNull; | |
+import com.google.inject.matcher.Matcher; | |
+import com.google.inject.spi.Dependency; | |
+ | |
+/** | |
+ * Immutable snapshot of a request to add a binding factory. | |
+ * | |
+ * @author stuart.mcculloch@jayway.net (Stuart McCulloch) | |
+ */ | |
+public final class AddBindingFactoryCommand<T> implements Command { | |
+ private final Object source; | |
+ private final Matcher<? super Dependency<? extends T>> dependencyMatcher; | |
+ private final BindingFactory<T> bindingFactory; | |
+ | |
+ AddBindingFactoryCommand( | |
+ Object source, | |
+ Matcher<? super Dependency<? extends T>> dependencyMatcher, | |
+ BindingFactory<T> bindingFactory) { | |
+ this.source = nonNull(source, "source"); | |
+ this.dependencyMatcher = nonNull(dependencyMatcher, "dependencyMatcher"); | |
+ this.bindingFactory = nonNull(bindingFactory, "bindingFactory"); | |
+ } | |
+ | |
+ public Object getSource() { | |
+ return source; | |
+ } | |
+ | |
+ public Matcher<? super Dependency<? extends T>> getDependencyMatcher() { | |
+ return dependencyMatcher; | |
+ } | |
+ | |
+ public BindingFactory<T> getBindingFactory() { | |
+ return bindingFactory; | |
+ } | |
+ | |
+ public <V> V acceptVisitor(Visitor<V> visitor) { | |
+ return visitor.visitAddBindingFactory(this); | |
+ } | |
+} | |
Property changes on: src/com/google/inject/commands/AddBindingFactoryCommand.java | |
___________________________________________________________________ | |
Name: svn:eol-style | |
+ native | |
Index: src/com/google/inject/commands/BindCommand.java | |
=================================================================== | |
--- src/com/google/inject/commands/BindCommand.java (revision 486) | |
+++ src/com/google/inject/commands/BindCommand.java (working copy) | |
@@ -22,8 +22,11 @@ | |
import com.google.inject.binder.LinkedBindingBuilder; | |
import com.google.inject.binder.ScopedBindingBuilder; | |
import com.google.inject.internal.ErrorMessages; | |
+import com.google.inject.internal.ErrorHandler; | |
import static com.google.inject.internal.Objects.nonNull; | |
+import com.google.inject.spi.Dependency; | |
import com.google.inject.spi.SourceProviders; | |
+import static com.google.inject.spi.SourceProviders.defaultSource; | |
import java.lang.annotation.Annotation; | |
@@ -123,18 +126,18 @@ | |
} | |
} | |
- BindingBuilder bindingBuilder(Binder binder) { | |
- return new BindingBuilder(binder); | |
+ BindingBuilder bindingBuilder(ErrorHandler errorHandler) { | |
+ return new BindingBuilder(errorHandler); | |
} | |
/** | |
* Package-private write access to the internal state of this command. | |
*/ | |
class BindingBuilder implements AnnotatedBindingBuilder<T> { | |
- private final Binder binder; | |
+ private final ErrorHandler errorHandler; | |
- BindingBuilder(Binder binder) { | |
- this.binder = binder; | |
+ BindingBuilder(ErrorHandler errorHandler) { | |
+ this.errorHandler = errorHandler; | |
} | |
public LinkedBindingBuilder<T> annotatedWith( | |
@@ -316,25 +319,25 @@ | |
private void checkNotTargetted() { | |
if (bindTarget != EMPTY_BIND_TARGET) { | |
- binder.addError(IMPLEMENTATION_ALREADY_SET); | |
+ errorHandler.handle(source, IMPLEMENTATION_ALREADY_SET); | |
} | |
} | |
private void checkNotAnnotated() { | |
if (BindCommand.this.key.getAnnotationType() != null) { | |
- binder.addError(ANNOTATION_ALREADY_SPECIFIED); | |
+ errorHandler.handle(source, ANNOTATION_ALREADY_SPECIFIED); | |
} | |
} | |
private void checkNotScoped() { | |
// Scoping isn't allowed when we have only one instance. | |
if (bindTarget.get() != null) { | |
- binder.addError(SINGLE_INSTANCE_AND_SCOPE); | |
+ errorHandler.handle(source, SINGLE_INSTANCE_AND_SCOPE); | |
return; | |
} | |
if (bindScoping != EMPTY_SCOPING) { | |
- binder.addError(SCOPE_ALREADY_SET); | |
+ errorHandler.handle(source, SCOPE_ALREADY_SET); | |
} | |
} | |
@@ -345,4 +348,22 @@ | |
return type + key.getTypeLiteral() + ">"; | |
} | |
} | |
+ | |
+ /** | |
+ * Attempt to add a missing binding to the injector by using a binding factory | |
+ */ | |
+ public static <B, T extends B> BindCommand<T> lateBinding(ErrorHandler errorHandler, | |
+ Dependency<T> dependency, BindingFactory<B> bindingFactory) { | |
+ | |
+ BindCommand<T> bindCommand = new BindCommand<T>( | |
+ defaultSource(), dependency.getKey()); | |
+ | |
+ LinkedBindingBuilder<T> lbb = bindCommand.bindingBuilder(errorHandler); | |
+ | |
+ if (bindingFactory.bind(dependency, lbb)) { | |
+ return bindCommand; | |
+ } else { | |
+ return null; | |
+ } | |
+ } | |
} | |
Index: src/com/google/inject/commands/Command.java | |
=================================================================== | |
--- src/com/google/inject/commands/Command.java (revision 486) | |
+++ src/com/google/inject/commands/Command.java (working copy) | |
@@ -38,5 +38,6 @@ | |
V visitConvertToTypes(ConvertToTypesCommand command); | |
<T> V visitBind(BindCommand<T> command); | |
<T> V visitGetProvider(GetProviderCommand<T> command); | |
+ <T> V visitAddBindingFactory(AddBindingFactoryCommand<T> command); | |
} | |
} | |
Index: src/com/google/inject/commands/CommandReplayer.java | |
=================================================================== | |
--- src/com/google/inject/commands/CommandReplayer.java (revision 486) | |
+++ src/com/google/inject/commands/CommandReplayer.java (working copy) | |
@@ -100,6 +100,11 @@ | |
replayGetProvider(binder, command); | |
return null; | |
} | |
+ | |
+ public <T> Void visitAddBindingFactory(AddBindingFactoryCommand<T> command) { | |
+ replayAddBindingFactory(binder, command); | |
+ return null; | |
+ } | |
}; | |
for (Command command : commands) { | |
@@ -199,4 +204,12 @@ | |
} | |
}); | |
} | |
+ | |
+ public <T> void replayAddBindingFactory(final Binder binder, final AddBindingFactoryCommand<T> command) { | |
+ SourceProviders.withDefault(command.getSource(), new Runnable() { | |
+ public void run() { | |
+ binder.addBindingFactory(command.getDependencyMatcher(), command.getBindingFactory()); | |
+ } | |
+ }); | |
+ } | |
} | |
Index: src/com/google/inject/commands/BindConstantCommand.java | |
=================================================================== | |
--- src/com/google/inject/commands/BindConstantCommand.java (revision 486) | |
+++ src/com/google/inject/commands/BindConstantCommand.java (working copy) | |
@@ -16,13 +16,13 @@ | |
package com.google.inject.commands; | |
-import com.google.inject.Binder; | |
import com.google.inject.Key; | |
import com.google.inject.Provider; | |
import com.google.inject.binder.AnnotatedConstantBindingBuilder; | |
import com.google.inject.binder.ConstantBindingBuilder; | |
import com.google.inject.binder.LinkedBindingBuilder; | |
import com.google.inject.binder.ScopedBindingBuilder; | |
+import com.google.inject.internal.ErrorHandler; | |
import com.google.inject.internal.Objects; | |
import static com.google.inject.internal.Objects.nonNull; | |
import com.google.inject.spi.SourceProviders; | |
@@ -102,8 +102,8 @@ | |
abstract <T> Key<T> getKey(); | |
} | |
- BindingBuilder bindingBuilder(Binder binder) { | |
- return new BindingBuilder(binder); | |
+ BindingBuilder bindingBuilder(ErrorHandler errorHandler) { | |
+ return new BindingBuilder(errorHandler); | |
} | |
/** | |
@@ -111,10 +111,10 @@ | |
*/ | |
class BindingBuilder | |
implements AnnotatedConstantBindingBuilder, ConstantBindingBuilder { | |
- private final Binder binder; | |
+ private final ErrorHandler errorHandler; | |
- BindingBuilder(Binder binder) { | |
- this.binder = binder; | |
+ BindingBuilder(ErrorHandler errorHandler) { | |
+ this.errorHandler = errorHandler; | |
} | |
public ConstantBindingBuilder annotatedWith(final Class<? extends Annotation> annotationType) { | |
@@ -349,13 +349,13 @@ | |
private void assertNoBindingAnnotation() { | |
if (bindingAnnotation != null) { | |
- binder.addError(ANNOTATION_ALREADY_SPECIFIED); | |
+ errorHandler.handle(source, ANNOTATION_ALREADY_SPECIFIED); | |
} | |
} | |
private void assertNoTarget() { | |
if (target != null) { | |
- binder.addError(CONSTANT_VALUE_ALREADY_SET); | |
+ errorHandler.handle(source, CONSTANT_VALUE_ALREADY_SET); | |
} | |
} | |
Index: src/com/google/inject/BindCommandProcessor.java | |
=================================================================== | |
--- src/com/google/inject/BindCommandProcessor.java (revision 486) | |
+++ src/com/google/inject/BindCommandProcessor.java (working copy) | |
@@ -299,6 +299,7 @@ | |
original.getSource()); | |
} else { | |
bindings.put(key, binding); | |
+ injector.index(binding); | |
} | |
} | |
Index: src/com/google/inject/InjectorBuilder.java | |
=================================================================== | |
--- src/com/google/inject/InjectorBuilder.java (revision 486) | |
+++ src/com/google/inject/InjectorBuilder.java (working copy) | |
@@ -17,11 +17,14 @@ | |
package com.google.inject; | |
import static com.google.inject.Scopes.SINGLETON; | |
+ | |
+import com.google.inject.commands.BindCommand; | |
import com.google.inject.commands.Command; | |
import com.google.inject.commands.CommandRecorder; | |
import com.google.inject.commands.FutureInjector; | |
import com.google.inject.internal.Objects; | |
import com.google.inject.internal.Stopwatch; | |
+import com.google.inject.spi.Dependency; | |
import com.google.inject.spi.SourceProviders; | |
import java.lang.reflect.Member; | |
@@ -98,6 +101,7 @@ | |
validate(); | |
errorHandler.switchToRuntime(); | |
+ injector.setMissingDependencyHandler(null); | |
// If we're in the tool stage, stop here. Don't eagerly inject or load | |
// anything. | |
@@ -141,13 +145,19 @@ | |
bindCommandProcesor = new BindCommandProcessor( | |
injector, injector.scopes, stage, injector.explicitBindings, | |
injector.outstandingInjections); | |
+ | |
+ AddBindingFactoryCommandProcessor addBindingFactoryCommandProcessor | |
+ = new AddBindingFactoryCommandProcessor(errorHandler); | |
+ addBindingFactoryCommandProcessor.processCommands(commands); | |
+ stopwatch.resetAndLog("Binding factory creation"); | |
+ | |
+ injector.setMissingDependencyHandler(new AddLateBindingHandler( | |
+ addBindingFactoryCommandProcessor.getBindingFactories())); | |
+ | |
bindCommandProcesor.processCommands(commands); | |
bindCommandProcesor.createUntargettedBindings(); | |
stopwatch.resetAndLog("Binding creation"); | |
- injector.index(); | |
- stopwatch.resetAndLog("Binding indexing"); | |
- | |
requestStaticInjectionCommandProcessor | |
= new RequestStaticInjectionCommandProcessor(errorHandler); | |
requestStaticInjectionCommandProcessor | |
@@ -261,4 +271,25 @@ | |
} | |
} | |
+ private final class AddLateBindingHandler implements MissingDependencyHandler { | |
+ final List<BindingFactory<?>> bindingFactories; | |
+ | |
+ public AddLateBindingHandler(List<BindingFactory<?>> bindingFactories) { | |
+ this.bindingFactories = bindingFactories; | |
+ } | |
+ | |
+ @SuppressWarnings("unchecked") | |
+ public boolean handle(Dependency dependency) { | |
+ | |
+ // search in order of registration... | |
+ for (BindingFactory bindingFactory : bindingFactories) { | |
+ BindCommand command = BindCommand.lateBinding(errorHandler, dependency, bindingFactory); | |
+ if (command != null) { | |
+ bindCommandProcesor.visitBind(command); | |
+ return true; | |
+ } | |
+ } | |
+ return false; | |
+ } | |
+ } | |
} | |
Index: src/com/google/inject/BindingFactory.java | |
=================================================================== | |
--- src/com/google/inject/BindingFactory.java (revision 0) | |
+++ src/com/google/inject/BindingFactory.java (revision 0) | |
@@ -0,0 +1,41 @@ | |
+/** | |
+ * Copyright (C) 2007 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 com.google.inject; | |
+ | |
+import com.google.inject.binder.LinkedBindingBuilder; | |
+import com.google.inject.spi.Dependency; | |
+ | |
+/** | |
+ * A factory capable of supplying bindings on request during construction of | |
+ * the {@code Injector}. Binding factories can be used to integrate service | |
+ * registries with Guice. | |
+ * | |
+ * @author stuart.mcculloch@jayway.net (Stuart McCulloch) | |
+ */ | |
+public interface BindingFactory<B> { | |
+ | |
+ /** | |
+ * Supplies bindings for missing dependencies that extend {@code B} | |
+ * | |
+ * @param <T> a type of dependency this factory can supply | |
+ * @param dependency the missing dependency that needs a binding | |
+ * @param linkedBindingBuilder a partially constructed binding | |
+ * @return true if this factory could supply a binding | |
+ */ | |
+ <T extends B> boolean bind(Dependency<T> dependency, | |
+ LinkedBindingBuilder<T> linkedBindingBuilder); | |
+} | |
Property changes on: src/com/google/inject/BindingFactory.java | |
___________________________________________________________________ | |
Name: svn:eol-style | |
+ native | |
Index: src/com/google/inject/MissingDependencyHandler.java | |
=================================================================== | |
--- src/com/google/inject/MissingDependencyHandler.java (revision 0) | |
+++ src/com/google/inject/MissingDependencyHandler.java (revision 0) | |
@@ -0,0 +1,32 @@ | |
+/** | |
+ * Copyright (C) 2007 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 com.google.inject; | |
+ | |
+import com.google.inject.spi.Dependency; | |
+ | |
+/** | |
+ * Handles missing dependencies in the Injector. | |
+ * | |
+ * @author stuart.mcculloch@jayway.net (Stuart McCulloch) | |
+ */ | |
+interface MissingDependencyHandler { | |
+ | |
+ /** | |
+ * Handles a missing dependency. | |
+ */ | |
+ boolean handle(Dependency<?> dependency); | |
+} | |
Property changes on: src/com/google/inject/MissingDependencyHandler.java | |
___________________________________________________________________ | |
Name: svn:eol-style | |
+ native | |
Index: src/com/google/inject/AbstractModule.java | |
=================================================================== | |
--- src/com/google/inject/AbstractModule.java (revision 486) | |
+++ src/com/google/inject/AbstractModule.java (working copy) | |
@@ -21,6 +21,7 @@ | |
import com.google.inject.binder.LinkedBindingBuilder; | |
import com.google.inject.internal.Objects; | |
import com.google.inject.matcher.Matcher; | |
+import com.google.inject.spi.Dependency; | |
import com.google.inject.spi.SourceProviders; | |
import com.google.inject.spi.TypeConverter; | |
import java.lang.annotation.Annotation; | |
@@ -186,4 +187,13 @@ | |
protected Stage currentStage() { | |
return binder.currentStage(); | |
} | |
+ | |
+ /** | |
+ * @see Binder#addBindingFactory | |
+ */ | |
+ protected <T> void addBindingFactory( | |
+ Matcher<? super Dependency<? extends T>> dependencyMatcher, | |
+ BindingFactory<T> bindingFactory) { | |
+ binder.addBindingFactory(dependencyMatcher, bindingFactory); | |
+ } | |
} | |
Index: src/com/google/inject/AddBindingFactoryCommandProcessor.java | |
=================================================================== | |
--- src/com/google/inject/AddBindingFactoryCommandProcessor.java (revision 0) | |
+++ src/com/google/inject/AddBindingFactoryCommandProcessor.java (revision 0) | |
@@ -0,0 +1,63 @@ | |
+/** | |
+ * 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 com.google.inject; | |
+ | |
+import com.google.inject.binder.LinkedBindingBuilder; | |
+import com.google.inject.commands.AddBindingFactoryCommand; | |
+import com.google.inject.internal.ErrorHandler; | |
+import com.google.inject.matcher.Matcher; | |
+import com.google.inject.spi.Dependency; | |
+import java.util.ArrayList; | |
+import java.util.Collections; | |
+import java.util.List; | |
+ | |
+/** | |
+ * Handles {@link Binder#addBindingFactory} commands. | |
+ * | |
+ * @author stuart.mcculloch@jayway.net (Stuart McCulloch) | |
+ */ | |
+final class AddBindingFactoryCommandProcessor extends CommandProcessor { | |
+ | |
+ private final List<BindingFactory<?>> bindingFactories = | |
+ new ArrayList<BindingFactory<?>>(); | |
+ | |
+ public AddBindingFactoryCommandProcessor(ErrorHandler errorHandler) { | |
+ super(errorHandler); | |
+ } | |
+ | |
+ @Override public <B> Boolean visitAddBindingFactory( | |
+ AddBindingFactoryCommand<B> command) { | |
+ | |
+ final Matcher<? super Dependency<? extends B>> dependencyMatcher = command.getDependencyMatcher(); | |
+ final BindingFactory<B> bindingFactory = command.getBindingFactory(); | |
+ | |
+ bindingFactories.add(new BindingFactory<B>() { | |
+ public <T extends B> boolean bind(Dependency<T> dependency, LinkedBindingBuilder<T> lbb) { | |
+ if (dependencyMatcher.matches(dependency)) { | |
+ return bindingFactory.bind(dependency, lbb); | |
+ } | |
+ return false; | |
+ } | |
+ }); | |
+ | |
+ return true; | |
+ } | |
+ | |
+ List<BindingFactory<?>> getBindingFactories() { | |
+ return Collections.unmodifiableList(bindingFactories); | |
+ } | |
+} | |
Property changes on: src/com/google/inject/AddBindingFactoryCommandProcessor.java | |
___________________________________________________________________ | |
Name: svn:eol-style | |
+ native | |
Index: src/com/google/inject/CommandProcessor.java | |
=================================================================== | |
--- src/com/google/inject/CommandProcessor.java (revision 486) | |
+++ src/com/google/inject/CommandProcessor.java (working copy) | |
@@ -91,4 +91,8 @@ | |
public <T> Boolean visitGetProvider(GetProviderCommand<T> command) { | |
return false; | |
} | |
+ | |
+ public <T> Boolean visitAddBindingFactory(AddBindingFactoryCommand<T> command) { | |
+ return false; | |
+ } | |
} | |
Index: src/com/google/inject/commands/DefaultCommandVisitor.java | |
=================================================================== | |
--- src/com/google/inject/commands/DefaultCommandVisitor.java (revision 486) | |
+++ src/com/google/inject/commands/DefaultCommandVisitor.java (working copy) | |
@@ -70,4 +70,8 @@ | |
RequestStaticInjectionCommand command) { | |
return visitCommand(command); | |
} | |
+ | |
+ public <T> V visitAddBindingFactory(AddBindingFactoryCommand<T> command) { | |
+ return visitCommand(command); | |
+ } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment