
com.google.gwt.inject.client.multibindings.GinMultibinder Maven / Gradle / Ivy
/*
* Copyright 2013 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.gwt.inject.client.multibindings;
import static com.google.gwt.inject.client.multibindings.TypeLiterals.providerOf;
import static com.google.gwt.inject.client.multibindings.TypeLiterals.setOf;
import com.google.gwt.inject.client.binder.GinBinder;
import com.google.gwt.inject.client.binder.GinLinkedBindingBuilder;
import com.google.gwt.inject.client.multibindings.InternalModule.SingletonInternalModule;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import java.lang.annotation.Annotation;
/**
* A utility that mimics the behavior and API of Guice Multibinder for GIN.
*
* Example usage:
*
* interface X {};
*
* class X1Impl implements X {};
*
* class X2Impl implements X {};
*
* class X3Provider implements Provider<X> { ... };
*
* Set<X> multibinder = GinMultibinder.newSetBinder(binder(), X.class);
* multibinder.addBinding().to(X1Impl.class);
* multibinder.addBinding().to(X2Impl.class);
* multibinder.addBinding().toProvier(X3Provider.class);
*
*
* @param type of value for Set
*/
public final class GinMultibinder {
/**
* Returns a new multibinder that collects instances of {@code type} in a {@link java.util.Set}
* that is itself bound with no binding annotation.
*/
public static GinMultibinder newSetBinder(GinBinder binder, TypeLiteral type) {
return newSetBinder(binder, type, Key.get(providerOf(type)));
}
/**
* Returns a new multibinder that collects instances of {@code type} in a {@link java.util.Set}
* that is itself bound with no binding annotation.
*/
public static GinMultibinder newSetBinder(GinBinder binder, Class type) {
return newSetBinder(binder, TypeLiteral.get(type));
}
/**
* Returns a new multibinder that collects instances of {@code type} in a {@link java.util.Set}
* that is itself bound with {@code annotation}.
*/
public static GinMultibinder newSetBinder(
GinBinder binder, TypeLiteral type, Annotation annotation) {
return newSetBinder(binder, type, Key.get(providerOf(type), annotation));
}
/**
* Returns a new multibinder that collects instances of {@code type} in a {@link java.util.Set}
* that is itself bound with {@code annotation}.
*/
public static GinMultibinder newSetBinder(
GinBinder binder, Class type, Annotation annotation) {
return newSetBinder(binder, TypeLiteral.get(type), annotation);
}
/**
* Returns a new multibinder that collects instances of {@code type} in a {@link java.util.Set}
* that is itself bound with {@code annotationType}.
*/
public static GinMultibinder newSetBinder(
GinBinder binder, TypeLiteral type, Class extends Annotation> annotationType) {
return newSetBinder(binder, type, Key.get(providerOf(type), annotationType));
}
/**
* Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
* itself bound with {@code annotationType}.
*/
public static GinMultibinder newSetBinder(
GinBinder binder, Class type, Class extends Annotation> annotationType) {
return newSetBinder(binder, TypeLiteral.get(type), annotationType);
}
private static GinMultibinder newSetBinder(
GinBinder ginBinder, TypeLiteral elementType, Key> keyForMultibinding) {
GinMultibinder multiBinder =
new GinMultibinder(ginBinder, elementType, keyForMultibinding);
multiBinder.install();
return multiBinder;
}
private final GinBinder ginBinder;
private final TypeLiteral elementType;
private final Key> multibindingKey;
public GinMultibinder(
GinBinder ginBinder, TypeLiteral elementType, Key> keyForMultibinding) {
this.ginBinder = ginBinder;
this.elementType = elementType;
this.multibindingKey = keyForMultibinding;
}
private void install() {
ginBinder.install(new RuntimeBindingsRegistryModule>(multibindingKey));
ginBinder.install(new SetModule());
}
/**
* Configures the bound set to silently discard duplicate elements. When multiple equal values are
* bound, the one that gets included is arbitrary. When multiple modules contribute elements to
* the set, this configuration option impacts all of them.
*/
public GinMultibinder permitDuplicates() {
ginBinder.install(new PermitDuplicatesModule>(multibindingKey));
return this;
}
/**
* Returns a binding builder used to add a new element in the set. Each bound element must have a
* distinct value. Bound providers will be evaluated each time the set is injected.
*
* It is an error to call this method without also calling one of the {@code to} methods on the
* returned binding builder.
*
* Scoping elements independently is supported. Use the {@code in} method to specify a binding
* scope.
*/
public GinLinkedBindingBuilder addBinding() {
return new BindingRecorder(ginBinder, multibindingKey).bind(elementType);
}
// TODO(user): not private due to http://code.google.com/p/google-gin/issues/detail?id=184
final class SetModule extends SingletonInternalModule> {
public SetModule() {
super(multibindingKey);
}
@Override
protected void configure() {
bindInternalBindingsRegistry();
bindAndExpose(setOf(elementType)).toProvider(Key.get(providerForSetOf(elementType)));
}
}
@SuppressWarnings("unchecked")
private static TypeLiteral> providerForSetOf(TypeLiteral type) {
return TypeLiterals.newParameterizedType(ProviderForSet.class, type);
}
}