Index: src/com/google/gwt/inject/rebind/BindingsProcessor.java |
=================================================================== |
--- src/com/google/gwt/inject/rebind/BindingsProcessor.java (revision 135) |
+++ src/com/google/gwt/inject/rebind/BindingsProcessor.java (working copy) |
@@ -27,6 +27,7 @@ |
import com.google.gwt.core.ext.typeinfo.NotFoundException; |
import com.google.gwt.inject.client.GinModule; |
import com.google.gwt.inject.client.GinModules; |
+import com.google.gwt.inject.client.Ginjector; |
import com.google.gwt.inject.rebind.adapter.GinModuleAdapter; |
import com.google.gwt.inject.rebind.adapter.GwtDotCreateProvider; |
import com.google.gwt.inject.rebind.binding.BindClassBinding; |
@@ -41,6 +42,7 @@ |
import com.google.gwt.inject.rebind.binding.ProviderMethodBinding; |
import com.google.gwt.inject.rebind.binding.RemoteServiceProxyBinding; |
import com.google.gwt.inject.rebind.binding.RequiredKeys; |
+import com.google.gwt.inject.rebind.binding.ToInstanceBinding; |
import com.google.gwt.inject.rebind.util.KeyUtil; |
import com.google.gwt.inject.rebind.util.MemberCollector; |
import com.google.gwt.inject.rebind.util.NameGenerator; |
@@ -119,7 +121,14 @@ |
* When this set and {@code unresolvedOptional} becomes empty, we know we've |
* satisfied all dependencies. |
*/ |
- private final Set<Key<?>> unresolved = new HashSet<Key<?>>(); |
+ private final Set<Key<?>> unresolved = new HashSet<Key<?>>() { |
+ public boolean add(com.google.inject.Key<?> e) { |
+ if (e.getTypeLiteral() != null && e.getTypeLiteral().getType() == Void.class) { |
+ throw new IllegalArgumentException(); |
+ } |
+ return super.add(e); |
+ }; |
+ }; |
/** |
* Set of keys for classes that we still need to resolve but that are |
@@ -128,6 +137,12 @@ |
* becomes empty, we know we've satisfied all dependencies. |
*/ |
private final Set<Key<?>> unresolvedOptional = new HashSet<Key<?>>(); |
+ |
+ /** |
+ * Set of instance-bound keys. Setter methods provide external references to objects |
+ * bound by toInstance() directive. |
+ */ |
+ private final Set<Key<?>> instances = new HashSet<Key<?>>(); |
/** |
* Collection of keys for which the ginjector interface provides member |
@@ -155,6 +170,7 @@ |
private final Provider<ImplicitProviderBinding> implicitProviderBindingProvider; |
private final Provider<ProviderMethodBinding> providerMethodBindingProvider; |
private final Provider<BindConstantBinding> bindConstantBindingProvider; |
+ private final Provider<ToInstanceBinding> instanceBindingProvider; |
private final Provider<GinjectorBinding> ginjectorBindingProvider; |
private final KeyUtil keyUtil; |
@@ -185,6 +201,7 @@ |
@GinjectorInterfaceType JClassType ginjectorInterface, |
LieToGuiceModule lieToGuiceModule, |
Provider<BindConstantBinding> bindConstantBindingProvider, |
+ Provider<ToInstanceBinding> instanceBindingProvider, |
Provider<RemoteServiceProxyBinding> remoteServiceProxyBindingProvider, |
Provider<ProviderMethodBinding> providerMethodBindingProvider, |
Provider<GinjectorBinding> ginjectorBindingProvider) { |
@@ -200,6 +217,7 @@ |
this.lieToGuiceModule = lieToGuiceModule; |
this.remoteServiceProxyBindingProvider = remoteServiceProxyBindingProvider; |
this.bindConstantBindingProvider = bindConstantBindingProvider; |
+ this.instanceBindingProvider = instanceBindingProvider; |
this.providerMethodBindingProvider = providerMethodBindingProvider; |
this.ginjectorBindingProvider = ginjectorBindingProvider; |
@@ -244,6 +262,9 @@ |
// http://code.google.com/p/google-gin/issues/detail?id=13 |
lieToGuiceModule.registerImplicitBinding(key); |
} |
+ if (instances.contains(key)) { |
+ lieToGuiceModule.registerInstanceBinding(key); |
+ } |
addBinding(key, binding); |
} else if (optional) { |
@@ -276,6 +297,7 @@ |
public GinScope determineScope(Key<?> key) { |
GinScope scope = getScopes().get(key); |
if (scope == null) { |
+ if (instances.contains(key)) return GinScope.INSTANCE; |
Class<?> raw = keyUtil.getRawType(key); |
if (raw.getAnnotation(Singleton.class) != null) { |
// Look for scope annotation as a fallback |
@@ -298,12 +320,18 @@ |
private void validateMethods() throws UnableToCompleteException { |
for (JMethod method : completeCollector.getMethods(ginjectorInterface)) { |
- if (method.getParameters().length > 1) { |
+ // void methods (setters) can have any number of params |
+ if (method.getReturnType().equals(JPrimitiveType.VOID)) { |
+ if (method.getParameters().length == 0) { |
+ logError("Injector setters should have at least one parameter, " |
+ + " found: " + method.getReadableDeclaration()); |
+ } |
+ } else if (method.getParameters().length > 1) { |
logError("Injector methods cannot have more than one parameter, " |
+ " found: " + method.getReadableDeclaration()); |
} |
- if (method.getParameters().length == 1) { |
+ if (method.getParameters().length == 1 && !KeyUtil.isInstanceSetter(method)) { |
// Member inject method. |
if (method.getParameters()[0].getType().isClassOrInterface() == null) { |
logError("Injector method parameter types must be a class or " |
@@ -315,8 +343,10 @@ |
+ "return type, found: " + method.getReadableDeclaration()); |
} |
} else if (method.getReturnType() == JPrimitiveType.VOID) { |
- // Constructor injection. |
- logError("Injector methods with no parameters cannot return void"); |
+ if (KeyUtil.isInstanceSetter(method) && method.getParameters().length == 0 || |
+ !KeyUtil.isInstanceSetter(method) && method.getParameters().length != 1) { |
+ logError("Wrong parameter count for void injector method: " + method.getReadableDeclaration()); |
+ } |
} |
} |
@@ -327,19 +357,26 @@ |
for (JMethod method : completeCollector.getMethods(ginjectorInterface)) { |
nameGenerator.markAsUsed(method.getName()); |
Key<?> key = keyUtil.getKey(method); |
- logger.log(TreeLogger.TRACE, "Add unresolved key from injector interface: " + key); |
+ if (key == null) { |
+ // collect instance keys |
+ RequiredKeys requiredKeys = keyUtil.getRequiredKeys(method); |
+ instances.addAll(requiredKeys.getRequiredKeys()); |
+ instances.addAll(requiredKeys.getOptionalKeys()); |
+ } else { |
+ logger.log(TreeLogger.TRACE, "Add unresolved key from injector interface: " + key); |
- // Member inject types do not need to be gin-creatable themselves but we |
- // need to provide all dependencies. |
- if (keyUtil.isMemberInject(method)) { |
- if (!unresolved.contains(key)) { |
- memberInjectRequests.add(key); |
- RequiredKeys requiredKeys = keyUtil.getRequiredKeys(keyUtil.getClassType(key)); |
- unresolved.addAll(requiredKeys.getRequiredKeys()); |
- unresolvedOptional.addAll(requiredKeys.getOptionalKeys()); |
+ // Member inject types do not need to be gin-creatable themselves but we |
+ // need to provide all dependencies. |
+ if (keyUtil.isMemberInject(method)) { |
+ if (!unresolved.contains(key)) { |
+ memberInjectRequests.add(key); |
+ RequiredKeys requiredKeys = keyUtil.getRequiredKeys(keyUtil.getClassType(key)); |
+ unresolved.addAll(requiredKeys.getRequiredKeys()); |
+ unresolvedOptional.addAll(requiredKeys.getOptionalKeys()); |
+ } |
+ } else { |
+ unresolved.add(key); |
} |
- } else { |
- unresolved.add(key); |
} |
} |
} |
@@ -421,6 +458,13 @@ |
} |
private Binding createImplicitBinding(Key<?> key, boolean optional) { |
+ // Instance binding |
+ if (instances.contains(key)) { |
+ getScopes().put(key, GinScope.INSTANCE); |
+ ToInstanceBinding bnd = new ToInstanceBinding(); |
+ return bnd; |
+ } |
+ |
// All steps per: |
// http://code.google.com/p/google-guice/wiki/BindingResolution |
@@ -493,7 +537,7 @@ |
if (providedBy != null) { |
return createProvidedByBinding(key, providedBy, optional); |
} |
- |
+ |
// 10. If the dependency is abstract or a non-static inner class, give up. |
// Abstract classes are handled by GWT.create. |
// TODO(schmitt): Introduce check. |
@@ -859,13 +903,15 @@ |
@Override |
public Void visit(InstanceBinding<? extends T> instanceBinding) { |
T instance = instanceBinding.getInstance(); |
- if (BindConstantBinding.isConstantKey(targetKey)) { |
+ if (BindConstantBinding.isConstantKey(targetKey) && |
+ instance != null && instance != ToInstanceBinding.DUMMY_INSTANCE) { |
BindConstantBinding binding = bindConstantBindingProvider.get(); |
binding.setKeyAndInstance(targetKey, instance); |
addBinding(targetKey, binding); |
} else { |
- messages.add(new Message(instanceBinding.getSource(), |
- "Instance binding not supported; key=" + targetKey + " inst=" + instance)); |
+ scopes.put(targetKey, GinScope.INSTANCE); |
+ ToInstanceBinding binding = instanceBindingProvider.get(); |
+ addBinding(targetKey, binding); |
} |
return null; |
@@ -919,7 +965,7 @@ |
} |
public Void visitNoScoping() { |
- scopes.put(targetKey, GinScope.NO_SCOPE); |
+ if (!scopes.containsKey(targetKey)) scopes.put(targetKey, GinScope.NO_SCOPE); |
return null; |
} |
} |