Skip to content

Instantly share code, notes, and snippets.

@gissuebot
Created July 7, 2014 19:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gissuebot/cdd1cee33023f9ede4fe to your computer and use it in GitHub Desktop.
Save gissuebot/cdd1cee33023f9ede4fe to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 778, comment 1
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