ratpack.guice.BindingsSpec Maven / Gradle / Ivy
Show all versions of ratpack-guice Show documentation
/*
* Copyright 2013 the original author or authors.
*
* 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 ratpack.guice;
import com.google.common.reflect.TypeToken;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.multibindings.Multibinder;
import ratpack.func.Action;
import ratpack.guice.internal.GuiceUtil;
import ratpack.registry.RegistrySpec;
import ratpack.server.ServerConfig;
import ratpack.util.Types;
import java.util.function.Supplier;
import static ratpack.util.Exceptions.uncheck;
/**
* A buildable specification of Guice bindings.
*
* This type is used when bootstrapping a Guice based application to add {@link Module modules} and bindings.
*
* It is recommended to become familiar with Guice bindings, scopes and other concerns before using Guice with Ratpack.
*
Module order and overrides
*
* The order in which modules are added is significant.
* Subsequent modules can override the bindings of previous modules.
* This is a very useful technique for augmenting/customising the functionality provided by modules.
* Many modules provide extensive bindings to facilitate such overriding.
*
* Bindings added via the {@code bind()} and {@code provider()} methods always have the highest precedence, regardless of order.
* That is, non module bindings can always override module bindings regardless of whether the module is added before or after the non module binding.
*/
public interface BindingsSpec extends RegistrySpec {
/**
* The launch config for the application.
*
* @return the launch config for the application
*/
ServerConfig getServerConfig();
/**
* Adds the bindings from the given module.
*
* @param module module whose bindings should be added
* @return this
*/
BindingsSpec module(Module module);
/**
* Adds the bindings from the given module.
*
* @param moduleClass type of the module whose bindings should be added
* @return this
*/
@SuppressWarnings("unchecked")
BindingsSpec module(Class extends Module> moduleClass);
/**
* Adds the bindings from the given configurable module.
*
* @param moduleClass type of the module whose bindings should be added
* @param configurer action to customize the module's config object
* @param the type of the module's config object
* @param the type of the module
* @return this
*/
> BindingsSpec module(Class moduleClass, Action super C> configurer);
/**
* Adds the bindings from the given configurable module.
*
* @param module module whose bindings should be added
* @param configurer action to customize the module's config object
* @param the type of the module's config object
* @return this
*/
BindingsSpec module(ConfigurableModule module, Action super C> configurer);
/**
* Adds the bindings from the given configurable module.
*
* @param moduleClass type of the module whose bindings should be added
* @param config config object for the module
* @param configurer action to customize the module's config object
* @param the type of the module's config object
* @param the type of the module
* @return this
*/
> BindingsSpec moduleConfig(Class moduleClass, C config, Action super C> configurer);
default > BindingsSpec moduleConfig(Class moduleClass, C config) {
return moduleConfig(moduleClass, config, Action.noop());
}
/**
* Adds the bindings from the given configurable module.
*
* @param module module whose bindings should be added
* @param config config object for the module
* @param configurer action to customize the module's config object
* @param the type of the module's config object
* @return this
*/
BindingsSpec moduleConfig(ConfigurableModule module, C config, Action super C> configurer);
default > BindingsSpec moduleConfig(T moduleClass, C config) {
return moduleConfig(moduleClass, config, Action.noop());
}
/**
* Adds bindings by directly configuring a {@link Binder}.
*
* @param action the binder configuration
* @return this
*/
BindingsSpec binder(Action super Binder> action);
default BindingsSpec multiBinder(TypeToken type, Action super Multibinder> action) throws Exception {
return binder(b -> action.execute(Multibinder.newSetBinder(b, GuiceUtil.toTypeLiteral(type))));
}
default BindingsSpec multiBinder(TypeLiteral type, Action super Multibinder> action) throws Exception {
return multiBinder(GuiceUtil.toTypeToken(type), action);
}
default BindingsSpec multiBinder(Class type, Action super Multibinder> action) throws Exception {
return multiBinder(TypeToken.of(type), action);
}
/**
* Add a binding for the given type.
*
* @param type the type to add a binding for
* @return this
*/
default BindingsSpec bind(Class> type) {
return binder(binder -> binder.bind(type));
}
default BindingsSpec multiBind(Class type) {
return uncheck(() -> multiBinder(type, b -> b.addBinding().to(type)));
}
/**
* Add a binding for the given public type, to the given implementation type.
*
* @param publicType the public type of the binding
* @param implType the class implementing the public type
* @param the public type of the binding
* @return this
*/
default BindingsSpec bind(Class publicType, Class extends T> implType) {
return bind(TypeLiteral.get(publicType), implType);
}
default BindingsSpec bind(TypeToken publicType, Class extends T> implType) {
return bind(GuiceUtil.toTypeLiteral(publicType), implType);
}
default BindingsSpec bind(TypeLiteral publicType, Class extends T> implType) {
return binder(binder -> binder.bind(publicType).to(implType));
}
default BindingsSpec multiBind(TypeLiteral publicType, Class extends T> implType) {
return uncheck(() -> multiBinder(publicType, b -> b.addBinding().to(implType)));
}
default BindingsSpec multiBind(Class publicType, Class extends T> implType) {
return multiBind(TypeLiteral.get(publicType), implType);
}
default BindingsSpec multiBind(TypeToken publicType, Class extends T> implType) {
return multiBind(GuiceUtil.toTypeLiteral(publicType), implType);
}
/**
* Add a binding for the given public type, to the given implementing instance.
*
* @param publicType the public type of the binding
* @param instance the instance that implements the public type
* @param the public type of the binding
* @return this
*/
default BindingsSpec bindInstance(TypeLiteral super T> publicType, T instance) {
return binder(b -> b.bind(publicType).toInstance(instance));
}
default BindingsSpec bindInstance(TypeToken super T> publicType, T instance) {
return bindInstance(GuiceUtil.toTypeLiteral(publicType), instance);
}
default BindingsSpec bindInstance(Class super T> publicType, T instance) {
return bindInstance(TypeLiteral.get(publicType), instance);
}
/**
* Add a binding for the given object to its concrete type.
*
* @param instance the instance to bind
* @param the type of the binding
* @return this
*/
default BindingsSpec bindInstance(T instance) {
if (instance instanceof Class) {
throw new IllegalArgumentException("cannot use bindInstance() with a class object (use bind(Class) instead)");
}
Class type = Types.cast(instance.getClass());
return binder(binder -> binder.bind(type).toInstance(instance));
}
default BindingsSpec multiBindInstance(Class publicType, T instance) {
return uncheck(() -> {
return multiBinder(publicType, b -> b.addBinding().toInstance(instance));
});
}
default BindingsSpec multiBindInstance(TypeLiteral publicType, T instance) {
return uncheck(() -> {
return multiBinder(publicType, b -> b.addBinding().toInstance(instance));
});
}
default BindingsSpec multiBindInstance(TypeToken publicType, T instance) {
return uncheck(() -> {
return multiBinder(publicType, b -> b.addBinding().toInstance(instance));
});
}
default BindingsSpec multiBindInstance(T instance) {
if (instance instanceof Class) {
throw new IllegalArgumentException("cannot use multiBindInstance() with a class object (use multiBind(Class) instead)");
}
Class type = Types.cast(instance.getClass());
return multiBindInstance(type, instance);
}
/**
* Add a binding for the given public type, to the given provider.
*
* @param publicType the public type of the object
* @param provider the provider for the object
* @param The public type of the object
* @return this
*/
default BindingsSpec provider(TypeLiteral publicType, Provider extends T> provider) {
return binder(b -> b.bind(publicType).toProvider(provider));
}
default BindingsSpec provider(TypeToken publicType, Provider extends T> provider) {
return provider(GuiceUtil.toTypeLiteral(publicType), provider);
}
default BindingsSpec provider(Class publicType, Provider extends T> provider) {
return provider(TypeLiteral.get(publicType), provider);
}
default BindingsSpec multiBindProvider(TypeLiteral publicType, Provider extends T> provider) {
return uncheck(() -> multiBinder(publicType, b -> b.addBinding().toProvider(provider)));
}
default BindingsSpec multiBindProvider(TypeToken publicType, Provider extends T> provider) {
return multiBindProvider(GuiceUtil.toTypeLiteral(publicType), provider);
}
default BindingsSpec multiBindProvider(Class publicType, Provider extends T> provider) {
return multiBindProvider(TypeLiteral.get(publicType), provider);
}
/**
* Add a binding for the given public type, to the given provider type.
*
* @param publicType the public type of the object
* @param providerType the type of the provider for the object
* @param The public type of the object
* @return this
*/
default BindingsSpec providerType(TypeLiteral publicType, Class extends Provider extends T>> providerType) {
return binder(binder -> binder.bind(publicType).toProvider(providerType));
}
default BindingsSpec providerType(Class publicType, Class extends Provider extends T>> providerType) {
return providerType(TypeLiteral.get(publicType), providerType);
}
default BindingsSpec providerType(TypeToken publicType, Class extends Provider extends T>> providerType) {
return providerType(GuiceUtil.toTypeLiteral(publicType), providerType);
}
default BindingsSpec multiBindProviderType(Class publicType, Class extends Provider extends T>> providerType) {
return uncheck(() -> multiBinder(publicType, b -> b.addBinding().toProvider(providerType)));
}
@Override
default RegistrySpec add(TypeToken super O> type, O object) {
return multiBindInstance(type, object);
}
@SuppressWarnings({"Anonymous2MethodRef", "Convert2Lambda"})
@Override
default RegistrySpec addLazy(TypeToken type, Supplier extends O> supplier) {
return multiBindProvider(type, new Provider() {
@Override
public O get() {
return supplier.get();
}
});
}
}