Mark code with @DeprecatedAfter("x.y.z") and have your build fail once the project's
version moves past that version — so deprecated code can't silently outlive its removal
window. Works identically under Gradle and Maven.
@DeprecatedAfter(value = "2.0.0", reason = "Legacy API", replacement = "NewApiClass")
public class OldApiClass { }Once the project version becomes strictly greater than 2.0.0 (e.g. 2.0.1), the build fails
until OldApiClass is removed.
- The
@DeprecatedAfterannotation hasCLASSretention — it is written to bytecode but not loaded at runtime, so you depend on it withcompileOnly/providedscope and ship nothing extra in your application. - A build-tool plugin scans your compiled classes (via ASM, no classloading) and compares each annotated element's version against the project version using Semantic Versioning.
- An element fails the build only when
projectVersionis strictly greater than its@DeprecatedAftervalue. Pre-releases sort below their release (2.0.0-SNAPSHOT<2.0.0), so a snapshot of the threshold version does not trip the gate.
All published to Maven Central under group com.lafeir:
| Artifact | Purpose |
|---|---|
deprecated-after-annotation |
The @DeprecatedAfter annotation (zero dependencies). Add to your project. |
deprecated-after-gradle-plugin |
Gradle plugin (id com.lafeir.deprecated-after). |
deprecated-after-maven-plugin |
Maven plugin (goal deprecated-after:check). |
deprecated-after-core |
Shared scanner + version logic. Pulled in transitively by the plugins. |
The plugin is published to Maven Central (not the Gradle Plugin Portal), so add mavenCentral()
to plugin resolution in settings.gradle.kts:
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}Then apply it and depend on the annotation in build.gradle.kts:
plugins {
java
id("com.lafeir.deprecated-after") version "0.1.0"
}
version = "1.0.0" // the version checked against @DeprecatedAfter
dependencies {
compileOnly("com.lafeir:deprecated-after-annotation:0.1.0")
}The plugin registers a validateDeprecatedAfter task and wires it into check, so it runs as
part of ./gradlew check (or ./gradlew build). Run it directly with:
./gradlew validateDeprecatedAfterDeclare the annotation as a provided dependency and bind the plugin to the build:
<dependencies>
<dependency>
<groupId>com.lafeir</groupId>
<artifactId>deprecated-after-annotation</artifactId>
<version>0.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.lafeir</groupId>
<artifactId>deprecated-after-maven-plugin</artifactId>
<version>0.1.0</version>
<executions>
<execution>
<goals><goal>check</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>The check goal binds to the verify phase by default, so it runs on mvn verify. Skip it with
-DdeprecatedAfter.skip=true.
import com.lafeir.deprecatedafter.DeprecatedAfter;
@DeprecatedAfter("1.5.0")
public void oldMethod() { }| Parameter | Required | Description |
|---|---|---|
value |
Yes | Version after which the element must be removed, e.g. "2.0.0". |
reason |
No | Reason for deprecation, shown in the failure message. |
replacement |
No | Suggested replacement, shown in the failure message. |
Applicable to classes/interfaces, methods/constructors, and fields.
@DeprecatedAfter validation failed! The following deprecated elements should be removed:
- com.example.OldApiClass (deprecated after version 2.0.0) - Reason: Legacy API - Use: NewApiClass
Current project version: 2.0.1
Versions are compared per Semantic Versioning 2.0.0:
- Numeric core compared field by field; missing trailing fields are treated as zero (
1.0==1.0.0). - A pre-release sorts below its release:
2.0.0-SNAPSHOTand2.0.0-alphaare both< 2.0.0. - Build metadata (
+sha) is ignored. - If the project version is unset/
unspecified, validation is skipped with a warning.
./gradlew build # compile + run all tests
./gradlew publishToMavenLocal # install all artifacts to ~/.m2 (signing skipped without a key)Publishing uses Gradle's built-in maven-publish + signing (no third-party publishing plugin)
and targets the Central Portal.
Prerequisites:
- Verify the
com.lafeirnamespace in the Central Portal (DNS TXT record onlafeir.com). - A Central Portal publishing token, exposed as:
ORG_GRADLE_PROJECT_mavenCentralUsernameORG_GRADLE_PROJECT_mavenCentralPassword
- A GPG signing key, exposed as:
ORG_GRADLE_PROJECT_signingInMemoryKey(ASCII-armored private key)ORG_GRADLE_PROJECT_signingInMemoryKeyPassword
Then build the upload bundle and post it to the Portal:
./gradlew clean publishAllPublicationsToStagingRepository centralBundle
curl --request POST \
--header "Authorization: Bearer $CENTRAL_PORTAL_TOKEN" \
--form bundle=@build/central/central-bundle-0.1.0.zip \
https://central.sonatype.com/api/v1/publisher/uploadApache License 2.0 — see the LICENSE file.