-
Notifications
You must be signed in to change notification settings - Fork 1.7k
RestrictedBindingSource
If you own a Guice library that provides a set of bindings, you may want to prevent code outside your library from providing them. Reasons include:
-
Preventing users from rolling their own fake implementation of your bindings in tests, in order to force them to use the canonical fake module your library maintains.
-
Letting alternate implementations of your set of bindings appear throughout your codebase makes it harder to refactor client code.
-
Guaranteeing a contract for downstream libraries. There can be invariants between your bindings that you want to guarantee by only allowing a limited set of vetted implementations - similar to how Guava guarantees the
ImmutableSet
contract by only allowing subclasses within the library.
The @RestrictedBindingSource
annotation lets you do this - it lets you
restrict which modules can provide your bindings. Annotating your bindings with
@RestrictedBindingSource
lets you specify a permit annotation that modules
providing them need to be annotated with. For example, this is how you would
ensure that @IpAddress Integer
and RoutingTable
bindings can only be
provided by NetworkModule
:
// Modules annotated with this Permit can provide Network bindings.
@RestrictedBindingSource.Permit
@Retention(RetentionPolicy.RUNTIME)
@interface NetworkPermit {}
// Bindings with the @IpAddress qualifier annotation can only be provided by
// modules with the NetworkPermit annotation.
@RestrictedBindingSource(
explanation = "Please install NetworkModule instead of binding network bindings yourself.",
permits = {NetworkPermit.class})
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface IpAddress {}
// The RoutingTable binding can only be provided by modules annotated with the
// NetworkPermit annotation.
@RestrictedBindingSource(
explanation = "Please install NetworkModule instead of binding network bindings yourself.",
permits = {NetworkPermit.class})
public interface RoutingTable {
int getNextHopIpAddress(int destinationIpAddress);
}
@NetworkPermit
public final class NetworkModule extends AbstractModule {
@Provides @IpAddress int provideIp( ... ) { ... }
@Override
protected void configure() {
// RoutingModule is permitted to provide the RoutingTable binding because
// it is installed by NetworkModule, which is annotated with NetworkPermit
// - ie. it's enough for any module providing a binding (directly or
// indirectly) to have the right permit.
install(new RoutingModule());
}
}
private final RoutingModule extends AbstractModule {
@Provides RoutingTable provideRoutingTable( ... ) { ... }
}
If the restriction is violated, the explanation
will be included in the error
message, pointing the user to the correct module to install for providing the
restricted binding. The explanation will also be included in the error message
if the restricted binding is missing -
again pointing the developer to the right module to install.
In addition to modules, ModuleAnnotatedMethodScanner
s are also a source of
bindings and can be annotated with permits to grant them permission to provide
restricted bindings.
For example, if a scanner scans @FooProvides
methods and binds types provided
by those methods to @Foo Type
, @Foo
can be restricted such that only the
scanner can provide bindings annotated with @Foo
.
-
User's Guide
-
Integration
-
Extensions
-
Internals
-
Releases
-
Community