All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.inject.multibindings.OptionalBinder Maven / Gradle / Ivy

package com.google.inject.multibindings;

import static com.google.inject.internal.RealOptionalBinder.newRealOptionalBinder;

import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.internal.RealOptionalBinder;

/**
 * An API to bind optional values, optionally with a default value.
 * OptionalBinder fulfills two roles: 
    *
  1. It allows a framework to define an injection point that may or * may not be bound by users. *
  2. It allows a framework to supply a default value that can be changed * by users. *
* *

When an OptionalBinder is added, it will always supply the bindings: {@code Optional} and * {@code Optional>}. Both {@link java.util.Optional java.util.Optional} and {@link * com.google.common.base.Optional com.google.common.base.Optional} are bound for compatibility. If * {@link #setBinding} or {@link #setDefault} are called, it will also bind {@code T}. * *

{@code setDefault} is intended for use by frameworks that need a default * value. User code can call {@code setBinding} to override the default. * Warning: Even if setBinding is called, the default binding * will still exist in the object graph. If it is a singleton, it will be * instantiated in {@code Stage.PRODUCTION}. * *

If setDefault or setBinding are linked to Providers, the Provider may return * {@code null}. If it does, the Optional bindings will be absent. Binding * setBinding to a Provider that returns null will not cause OptionalBinder * to fall back to the setDefault binding. * *

If neither setDefault nor setBinding are called, it will try to link to a * user-supplied binding of the same type. If no binding exists, the optionals * will be absent. Otherwise, if a user-supplied binding of that type exists, * or if setBinding or setDefault are called, the optionals will return present * if they are bound to a non-null value. * *

Values are resolved at injection time. If a value is bound to a * provider, that provider's get method will be called each time the optional * is injected (unless the binding is also scoped, or an optional of provider is * injected). * *

Annotations are used to create different optionals of the same key/value * type. Each distinct annotation gets its own independent binding. * *


 * public class FrameworkModule extends AbstractModule {
 *   protected void configure() {
 *     OptionalBinder.newOptionalBinder(binder(), Renamer.class);
 *   }
 * }
* *

With this module, an {@code Optional} can now be * injected. With no other bindings, the optional will be absent. * Users can specify bindings in one of two ways: * *

Option 1: *


 * public class UserRenamerModule extends AbstractModule {
 *   protected void configure() {
 *     bind(Renamer.class).to(ReplacingRenamer.class);
 *   }
 * }
* *

or Option 2: *


 * public class UserRenamerModule extends AbstractModule {
 *   protected void configure() {
 *     OptionalBinder.newOptionalBinder(binder(), Renamer.class)
 *         .setBinding().to(ReplacingRenamer.class);
 *   }
 * }
* With both options, the {@code Optional} will be present and supply the * ReplacingRenamer. * *

Default values can be supplied using: *


 * public class FrameworkModule extends AbstractModule {
 *   protected void configure() {
 *     OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
 *         .setDefault().toInstance(DEFAULT_LOOKUP_URL);
 *   }
 * }
* With the above module, code can inject an {@code @LookupUrl String} and it * will supply the DEFAULT_LOOKUP_URL. A user can change this value by binding *

 * public class UserLookupModule extends AbstractModule {
 *   protected void configure() {
 *     OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
 *         .setBinding().toInstance(CUSTOM_LOOKUP_URL);
 *   }
 * }
* ... which will override the default value. * *

If one module uses setDefault the only way to override the default is to use setBinding. * It is an error for a user to specify the binding without using OptionalBinder if * setDefault or setBinding are called. For example, *


 * public class FrameworkModule extends AbstractModule {
 *   protected void configure() {
 *     OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
 *         .setDefault().toInstance(DEFAULT_LOOKUP_URL);
 *   }
 * }
 * public class UserLookupModule extends AbstractModule {
 *   protected void configure() {
 *     bind(Key.get(String.class, LookupUrl.class)).toInstance(CUSTOM_LOOKUP_URL);
 *   }
 * }
* ... would generate an error, because both the framework and the user are trying to bind * {@code @LookupUrl String}. */ public class OptionalBinder { // This class is non-final due to users mocking this in tests :( public static OptionalBinder newOptionalBinder(Binder binder, Class type) { return new OptionalBinder<>( newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type))); } public static OptionalBinder newOptionalBinder(Binder binder, TypeLiteral type) { return new OptionalBinder<>( newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type))); } public static OptionalBinder newOptionalBinder(Binder binder, Key type) { return new OptionalBinder<>( newRealOptionalBinder(binder.skipSources(OptionalBinder.class), type)); } private final RealOptionalBinder delegate; private OptionalBinder(RealOptionalBinder delegate) { this.delegate = delegate; } /** * Returns a binding builder used to set the default value that will be injected. The binding set * by this method will be ignored if {@link #setBinding} is called. * *

It is an error to call this method without also calling one of the {@code to} methods on the * returned binding builder. */ public LinkedBindingBuilder setDefault() { return delegate.setDefault(); } /** * Returns a binding builder used to set the actual value that will be injected. This overrides * any binding set by {@link #setDefault}. * *

It is an error to call this method without also calling one of the {@code to} methods on the * returned binding builder. */ public LinkedBindingBuilder setBinding() { return delegate.setBinding(); } // Some tests depend on equals/hashCode behavior of OptionalBinder @Override public boolean equals(Object obj) { if (obj instanceof OptionalBinder) { return delegate.equals(((OptionalBinder) obj).delegate); } return false; } @Override public int hashCode() { return delegate.hashCode(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy