docs/api_guidelines/annotations.md
Annotation processors should opt-in to incremental annotation processing to avoid triggering a full recompilation on every client source code change. See Gradle's Incremental annotation processing documentation for information on how to opt-in.
@RequiresOptIn APIs {#experimental-api}Jetpack libraries may choose to annotate API surfaces as unstable using either
Kotlin's
@RequiresOptIn meta-annotation
for APIs written in Kotlin or Jetpack's
@RequiresOptIn meta-annotation
for APIs written in Java.
@RequiresOptInat-a-glance:
- Use for unstable API surfaces
- Can be called by anyone
- Documented in public documentation
- Does not maintain compatibility
For either annotation, API surfaces marked as opt-in are considered alpha and
will be excluded from API compatibility guarantees. Due to the lack of
compatibility guarantees, stable libraries must never call experimental APIs
exposed by other libraries outside of their
same-version group and may not use the @OptIn
annotation except in the following cases:
@OptIn annotation to prevent propagation of
the experimental property. Library owners must exercise care to ensure
that post-alpha APIs backed by experimental APIs actually meet the release
criteria for post-alpha APIs.alpha library may use experimental APIs from outside its same-version
group. These usages must be removed when the library moves to beta.NOTE JetBrains's own usage of @RequiresOptIn in Kotlin language libraries
varies and may indicate binary instability, functional instability, or simply
that an API is really difficult to use. Jetpack libraries should treat instances
of @RequiresOptIn in JetBrains libraries as indicating binary instability
and avoid using them outside of alpha; however, teams are welcome to obtain
written assurance from JetBrains regarding binary stability of specific APIs.
@RequiresOptIn APIs that are guaranteed to remain binary compatible may be
used in beta, but usages must be removed when the library moves to rc.
Do not use @RequiresOptIn for a stable API surface that is difficult to use.
It is not a substitute for a properly-designed API surface.
Do not use @RequiresOptIn for an API surface that is unreliable or unstable
because it is missing tests. It is not a substitute for a properly-tested API
surface, and all APIs -- including those in alpha -- are expected to be
functionally stable.
Do not use @RequiresOptIn for an internal-facing API surface. Use either the
appropriate language visibility (ex. private or internal) or @RestrictTo.
Do not use @RequiresOptIn for an API that you expect library developers to
call. Experimental APIs do not maintain binary compatibility guarantees, and you
will put external clients in a difficult situation.
Do use @RequiresOptIn for API surfaces that must be publicly available and
documented but need the flexibility to stay in alpha during the rest of the
library's beta, rc, or stable cycles, and continue to break compatibility in
beta.
All libraries using @RequiresOptIn annotations must depend on the
androidx.annotation:annotation-experimental artifact regardless of whether
they are using the androidx or Kotlin annotation. This artifact provides Lint
enforcement of experimental usage restrictions for Kotlin callers as well as
Java (which the Kotlin annotation doesn't handle on its own, since it's a Kotlin
compiler feature). Libraries may include the dependency as api-type to make
@OptIn available to Java clients; however, this will also unnecessarily expose
the @RequiresOptIn annotation.
dependencies {
implementation(project(":annotation:annotation-experimental"))
}
See Kotlin's
opt-in requirements documentation
for general usage information. If you are writing experimental Java APIs, you
will use the Jetpack
@RequiresOptIn annotation
rather than the Kotlin compiler's annotation.
When an API surface is ready to transition out of experimental, the annotation may only be removed during an alpha pre-release stage. Removing the experimental marker from an API is equivalent to adding the API to the current API surface.
When transitioning an entire feature surface out of experimental, you should remove the definition for the associated experimental marker annotation.
When making any change to the experimental API surface, you must run
./gradlew updateApi prior to uploading your change.
NOTE Experimental marker annotation are themselves experimental, meaning that it's considered binary compatible to refactor or remove an experimental marker annotation.
Note: Experimental APIs are reviewed by API Council both when the APIs are first introduced, and when they are stabilized. API Council may have additional feedback during stabilization.
@RestrictTo APIs {#restricted-api}Jetpack's library tooling supports hiding JVM-visible (ex. public and
protected) APIs from developers using a combination of the @RestrictTo
source annotation.
@RestrictToat-a-glance:
- Use for internal-facing API surfaces
- Can be called within the specified
Scope- Does not appear in public documentation
- Does not maintain compatibility in most scopes
While restricted APIs do not appear in documentation and Android Studio will warn against calling them, hiding an API does not provide strong guarantees about usage:
These annotations indicate that developers should not call an API that is technically public from a JVM visibility perspective. Hiding APIs is often a sign of a poorly-abstracted API surface, and priority should be given to creating public, maintainable APIs and using Java visibility modifiers.
Do not use @RestrictTo to bypass API tracking and review for production
APIs; instead, rely on API+1 and API Council review to ensure APIs are reviewed
on a timely basis.
Do not use @RestrictTo for implementation detail APIs that are used between
libraries and could reasonably be made public.
Do use @RestrictTo(LIBRARY) for implementation detail APIs used within a
single library (but prefer Java language private or default visibility).
RestrictTo.Scope and inter- versus intra-library API surfaces {#private-api-types}To maintain binary compatibility between different versions of libraries,
restricted API surfaces that are used between libraries within Jetpack
(inter-library APIs) must follow the same Semantic Versioning rules as public
APIs. Inter-library APIs should be annotated with the
@RestrictTo(LIBRARY_GROUP) source annotation.
Restricted API surfaces used within a single library (intra-library APIs), on
the other hand, may be added or removed without any compatibility
considerations. It is safe to assume that developers never call these APIs,
even though it is technically feasible. Intra-library APIs should be annotated
with the @RestrictTo(LIBRARY) source annotation.
In all cases, correctness and compatibility tracking are handled by AndroidX's build system and lint checks.
The following table shows the visibility of a hypothetical API within Maven
coordinate androidx.concurrent:concurrent when annotated with a variety of
scopes:
@VisibleForTestingFor library APIs that should only be used from test code -- including the
library's own tests, integration test apps, app developers' tests, or
third-party testing libraries -- use the @VisibleForTesting annotation to
ensure that the API is only called from test source sets.
Libraries targeted at multi-platform usage in IntelliJ may use @TestOnly to
ensure that the IDE enforces usage restrictions.
Jetpack prefers that libraries expose test APIs as public API and maintain binary compatibility. This ensures that whatever a library needs in its own integration test app is available to app developers and may be safely called in third-party testing libraries.
In cases where a test API needs restricted visibility or flexibility around
binary compatibility, the @VisibleForTesting annotation may be combined with a
@RestrictTo scope or @RequiresOptIn feature group.
@IntDef @StringDef and @LongDef and visibilityAll @IntDef, @StringDef, and @LongDef will be stripped from resulting
artifacts to avoid issues where compiler inlining constants removes information
as to which @IntDef defined the value of 1. The annotations are extracted
and packaged separately to be read by Android Studio and lint which enforces the
types in application code.
@RestrictTo all @IntDef, @StringDef, and @LongDef
declarations to create a warning when the type is used incorrectly.@IntDef etc at the
same Java visibility as the hidden @IntDefHere is a complete example of an @IntDef
// constants match Java visibility of ExifStreamType
// code outside this module interacting with ExifStreamType uses these constants
public static final int STREAM_TYPE_FULL_IMAGE_DATA = 1;
public static final int STREAM_TYPE_EXIF_DATA_ONLY = 2;
@RestrictTo(RestrictTo.Scope.LIBRARY) // Don't export ExifStreamType outside module
@Retention(RetentionPolicy.SOURCE)
@IntDef({
STREAM_TYPE_FULL_IMAGE_DATA,
STREAM_TYPE_EXIF_DATA_ONLY,
})
public @interface ExifStreamType {}
Java visibility should be set as appropriate for the code in question
(private, package, or public) and is unrelated to hiding.
For more, read the section in Android API Council Guidelines
*current.txt File Explanation {#currenttxt}In this example, 1.3.0-beta02.txt is just used for an example. This will match
the current library version.