Remove Deprecated API — AEM as a Cloud Service
This pattern is executed by the code-assessment runbook — follow
../references/runbook.mdfor the outer flow (preflight → plan → apply → verify, run log). This skill supplies the plugin-driven detection and the hint-driven fix recipe the runbook applies.
Overview
Adobe curates the list of deprecated / removed AEM APIs inside the AEM SDK's
api-regions metadata; Cloud Manager's region-deprecated-api analyser task consumes
that JSON at build time. The AEM Analyser Maven Plugin
(com.adobe.aem:aemanalyser-maven-plugin) runs the same task locally against the
project's built bundles. This skill uses the plugin as its detection engine — no
curated tables, no static lists, no drift.
For each deprecated package the plugin reports, its log line contains a hint: the
deprecated.msg field from the SDK metadata, which typically names a successor
package (e.g. "Please use org.apache.sling.xss instead"). Fixes are derived from
that hint at plan time. When the hint names no successor, the recipe consults the
Adobe Experience League API-removal guidance as a documented fallback.
Classification — confirm this pattern applies
- Any
*.java,pom.xml, or OSGi config file the AEM Analyser Maven Plugin reports underregion-deprecated-api(i.e. anyUsage of deprecated ... foundlog line produced bymvn verifyagainst the project). - Cloud Manager code-quality pipeline failures citing
region-deprecated-api,api-regions-check,Import-Package not satisfied, orbundle-unversioned-packagesviolations.
The plugin only reports past-due deprecations by default (entries whose
for-removal date has already elapsed). Future-dated deprecations are not touched;
re-running the skill after each removal date passes picks them up automatically — the
list is live.
Discovery — two-phase
The detector lives in the shared Java analyzer (scripts/analyzer/detectors/RemoveDeprecatedApi.java),
same shape as every other pattern's detector — but its rules are loaded at run time
from a preflight-produced cache, not hardcoded.
Phase 1 — preflight (populates the rules cache)
bash plugins/aem/cloud-service/skills/code-assessment/remove-deprecated-api/scripts/detect.sh <project-root>
detect.sh:
- Resolves the latest
com.adobe.aem:aemanalyser-maven-pluginand the latestcom.adobe.aem:aem-sdk-apireleases from Maven Central (maven-metadata.xml); each can be pinned with--pin-plugin <version>/--pin-sdk <version>. The freshest SDK is used by default because Cloud Manager itself runs the analyser against the latest SDK — matching that behaviour surfaces every deprecation the pipeline will flag. If the project'spom.xmlpins an older SDK via<sdkVersion>X.Y.Z</sdkVersion>or<useDependencyVersions>true</useDependencyVersions>inside the analyser plugin config,detect.shoverrides at the CLI (-DsdkVersion=<latest>and-DsdkUseDependency=false) so the fresh set is used just for the preflight — no pom edit. Pass--respect-pom-sdkto honour the pom's pin instead. - Invokes the analyser by its fully-qualified
com.adobe.aem:aemanalyser-maven-plugin:<version>:project-analysecoordinates, so the resolved version runs whether or not the project declares the plugin — the pom is never modified (no patch, no backup, no restore). Command shape:mvn package com.adobe.aem:aemanalyser-maven-plugin:<version>:project-analyse …— thepackagephase (override with--goal) builds the module artifacts thatproject-analyseinspects. Log path:/tmp/aem-analyser.log(override with--log <path>). - Parses
Usage of deprecated package found : <pkg> : <hint> Deprecated since <since> For removal : <date>andUsage of deprecated library found : <lib>, package(s) : <start>...<end> : <hint>lines. - Writes the rules cache TSV —
<package>\t<hint>\t<for_removal>per line — at$AEM_DEPRECATED_API_RULES(env override) or$TMPDIR/aem-code-assessment/deprecated-api-rules.tsv(default). - Emits a JSON summary on stdout (findings + meta) for callers that don't chain
through
analyze.sh.
Phase 2 — analyzer (consumes the cache, emits findings)
bash plugins/aem/cloud-service/skills/code-assessment/scripts/analyze.sh <workspace-root>
The Java RemoveDeprecatedApi detector reads the rules TSV, matches each rule's
package against every import in the corpus (longest-prefix match), applies today's
past-due gating as a defence-in-depth, and emits findings in the standard
{pattern,file,line,snippet} shape with an added hint field carrying the analyser
message.
Findings shape — the standard runbook shape plus an optional hint:
{
"findings": [
{
"pattern": "remove-deprecated-api",
"file": "core/src/main/java/com/example/MyService.java",
"line": 5,
"snippet": "org.apache.log4j.Logger",
"hint": "The log4j 1.x libraries are deprecated. Please use org.slf4j instead."
}
],
"warnings": []
}
If the cache is missing — detect.sh was not run, or was run offline and failed —
the detector emits a single warning:
deprecated-api-rules-missing: expected TSV at <path> — run remove-deprecated-api/scripts/detect.sh preflight first
and produces no findings for this pattern. Other detectors continue unaffected.
Scope: workspace roots only. Exclude code-assessment/ skill files.
Resolution contract
hint-driven — every fix derives from the analyser's hint field for that finding.
The recipe (recipe.md Step 3) parses the hint for a successor-package phrase
("Please use X instead", "Use X instead", "X should be used") and applies the
edit. When the hint names no successor, the recipe falls back to Adobe Experience
League's API-removal guidance page via WebFetch.
Verification — before applying, the successor must be resolvable on the project's classpath. If it is not, either add the required Maven dependency (with user consent) or record the finding as manual-action-required.
Manual-only items (cannot be auto-fixed; document in report, do not attempt edits):
- Deep integration cases where hint says "not supported in AEM as a Cloud Service"
with no successor named on Experience League (e.g.
org.apache.felix.webconsole, parts ofcom.drew). - Guava usage beyond simple
Lists.newArrayList()/ImmutableList.of()— caching, event bus, complex data structures — where replacement requires design decisions. - Reflection or dynamic loading against the deprecated type — the scanner cannot see it and the fix is not mechanical.
Review checklist
- Latest
aemanalyser-maven-pluginresolved from Maven Central - Initial build passed before any transformations (
mvn compile) - Analyser log parsed; findings carry a non-empty
hintwhere the SDK provides one - Each finding's successor package (from hint or Experience League) verified on the classpath before applying
- Step 3 edits applied surgically (imports rewritten, deps updated, OSGi configs deleted where the plugin reports them as unmodifiable)
- Post-edit build checked; residual compilation errors routed to AI-fix phase
- Each AI-assisted fix marked with
// Fixed by AEM Modernizer AIabove the change - Final build passes and the analyser — re-invoked via the fully-qualified
project-analysegoal — now reports zero past-due deprecations - Manual-action items documented in the report
Troubleshooting fingerprints
| Symptom | Likely cause | Action |
|---|---|---|
detect.sh fails at plugin resolution step |
Plugin not in local Maven cache | Pass --pin-plugin <version> with a locally available version |
| The build fails before the analyser goal runs | Baseline compile failure in the package phase |
Fix the baseline build first (per runbook), then re-run detection |
| Hint is empty for a finding | SDK deprecation message is descriptive only, or the finding came from library grouping without a msg |
Consult Experience League for the successor; if still absent, record as manual-only |
Import-Package not satisfied on rerun |
Successor package not on the module's classpath | Add the required Maven dependency (with user consent) or pick a JDK stdlib alternative |
Analyser reports a package with no import match in-workspace |
Deprecated API pulled in transitively by a third-party bundle | Cannot fix in customer code; report as third-party dependency upgrade needed |
Recipe pointer
Read recipe.md fully before applying. The recipe covers the plugin
setup + preflight scan, the hint parsing rules, the Experience League fallback flow,
the AI-fix loop for compilation errors introduced by rewrites, and the report format.