com.google.inject.RestrictedBindingSource Maven / Gradle / Ivy
package com.google.inject;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* Annotation restricting the binding of the target type to permitted sources.
*
* Bindings restricted by this annotation may only be created by sources annotated with a permit
* from {@link #permits} -- otherwise, an error message including the {@link #explanation} is
* issued.
*
*
There are two kinds of binding source:
*
*
* - Module: a module is the source of a binding if it creates it (either directly, or
* indirectly by installing another module). For example: if module A creates restricted
* binding X, and module C installs module B that installs A; then all 3 modules C,B,A are
* sources of X, and it's enough for any one of them to be annotated with a permit from X's
* restriction.
*
- Method Scanner ({@code ModuleAnnotatedMethodScanner}): If a binding was created by a
* scanner, then that scanner is also a source of the binding (in addition to the module
* sources) and a permit may be given to the scanner by annotating its class.
*
*
* Bindings with qualifier annotations are restricted solely by the annotation on their qualifier
* (restrictions on the type are ignored for qualified bindings). Unqualified bindings are
* restricted by the annotation on their type.
*
*
This allows libraries to prevent their clients from binding their keys, similar to how
* declaring a class final prevents subtyping. For example, a library may want to prevent users from
* creating mock bindings for tests, using the {@link #explanation} - included in the error message
* - to point them to a supported testing module.
*
*
Example usage:
*
*
* {@literal @}RestrictedBindingSource.Permit
* {@literal @}Retention(RetentionPolicy.RUNTIME)
* {@literal @}interface NetworkPermit {}
*
* {@literal @}RestrictedBindingSource(
* explanation = "Only NetworkModule can create network bindings.",
* permits = {NetworkPermit.class})
* {@literal @}Qualifier
* {@literal @}Retention(RetentionPolicy.RUNTIME)
* public {@literal @}interface GatewayIpAdress {}
*
* {@literal @}NetworkPermit
* public final class NetworkModule extends AbstractModule {
* // Allowed because the module is annotated with {@literal @}NetworkPermit.
* {@literal @}Provides
* {@literal @}GatewayIpAdress
* int provideGatewayIp() { ... }
* }
*
*
* @author [email protected] (Vladimir Makaric)
* @since 5.0
*/
@Inherited
@Retention(RUNTIME)
@Target(TYPE)
public @interface RestrictedBindingSource {
/**
* Explanation of why binding this target type is restricted.
*
* Will appear as the error message if the target type is bound by non-allowed modules.
*/
String explanation();
/**
* Meta-annotation indicating that the target annotation is a permit for binding restricted
* bindings. Annotating a binding source (defined in top-level javadoc) with a permit gives it
* permission to bind the restricted bindings guarded by the permit (see {@link #permits}).
*
* @since 5.0
*/
@Documented
@Retention(RUNTIME)
@Target(ANNOTATION_TYPE)
public @interface Permit {}
/**
* List of {@code Permit} annotations (must be non-empty), one of which has has to be present on a
* restricted binding's source (defined in top-level javadoc).
*/
Class extends Annotation>[] permits();
/**
* Exempt modules whose fully qualified class names match this regex.
*
*
If any module on the binding's module stack matches this regex, the binding is allowed (no
* permit necessary). No module is exempt by default (empty string).
*
*
Inteded to be used when retrofitting a binding with this restriction. When restricting an
* existing binding, it's often practical to first restrict with exemptions for existing
* violations (to prevent new violations), before updating the code in violation to use the
* permitted module(s).
*/
String exemptModules() default "";
/**
* Level of restriction. Determines how violations are handled.
*
* @since 5.0
*/
public static enum RestrictionLevel {
WARNING,
ERROR;
}
RestrictionLevel restrictionLevel() default RestrictionLevel.ERROR;
}