Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Example - Shadow API Detector Request Mapping Composed Build
on:
push:
paths:
- 'examples/shadow-api-detector/request-mapping-composed/**/*.java'
- 'examples/shadow-api-detector/request-mapping-composed/**/*.yaml'
- 'examples/shadow-api-detector/request-mapping-composed/**/*.gradle'
- 'examples/shadow-api-detector/request-mapping-composed/**/*.properties'
- 'examples/shadow-api-detector/request-mapping-composed/**/libs.versions.toml'
- '.github/workflows/example-shadow-api-detector-request-mapping-composed-build.yml'

jobs:
Build-Example:
name: Build Example
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 1
persist-credentials: false

- name: Setup Java
uses: actions/setup-java@ad2b38190b15e4d6bdf0c97fb4fca8412226d287 # v5.3.0
with:
distribution: 'temurin'
java-version: 21

- name: Setup Gradle
uses: gradle/actions/setup-gradle@3f131e8634966bd73d06cc69884922b02e6faf92 # v6.2.0

- name: Build example
run: |
cd examples/shadow-api-detector/request-mapping-composed
chmod +x ./gradlew
./gradlew detectShadowApis --no-daemon
2 changes: 2 additions & 0 deletions examples/README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,5 @@ include::shadow-api-detector/with-shadow-apis/README.adoc[leveloffset=+1]
include::shadow-api-detector/multi-file-openapi/README.adoc[leveloffset=+1]

include::shadow-api-detector/openapi-3-2/README.adoc[leveloffset=+1]

include::shadow-api-detector/request-mapping-composed/README.adoc[leveloffset=+1]
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
= Shadow API Detector — Composed RequestMapping Example
:toc: left

== Description

This example applies the Shadow API Detector plugin to a small `LibraryController` that uses `@RequestMapping` at both levels.
The controller has a class-level `@RequestMapping("/library")` and method-level `@RequestMapping(path = ..., method = ...)` declarations.
The accompanying OpenAPI document describes every composed endpoint.
`rootDocument` is the only property configured because every other property already defaults correctly for this example's layout.

== Intent

This example demonstrates that endpoint composition from class-level and handler-level `@RequestMapping` is detected correctly.
It also demonstrates that no false positives are reported when those composed endpoints are fully documented.

== The Controller

[source,java]
----
@RestController
@RequestMapping("/library")
public class LibraryController {

@RequestMapping(path = "/books", method = RequestMethod.GET)
public String listBooks() { ... }

@RequestMapping(path = "/books/{id}", method = RequestMethod.GET)
public String getBook(@PathVariable Long id) { ... }

@RequestMapping(path = "/books", method = RequestMethod.POST)
public String addBook(@RequestBody String book) { ... }
}
----

Full source: `src/main/java/com/arc_e_tect/example/library/LibraryController.java`.
The matching OpenAPI document is `src/main/resources/openapi/openapi.yaml`.
The described paths are `/library/books` and `/library/books/{id}`.

== Build And Run

[source,bash]
----
cd examples/shadow-api-detector/request-mapping-composed
./gradlew detectShadowApis
----

== What To Expect

The build is expected to pass.
The plugin writes `build/reports/shadow-api-detector/shadow-apis.adoc`.
The report opens with a preamble explaining what a shadow API is (omitted below for brevity).
See link:../../../shadow-api-detector/README.adoc[the plugin README]'s "Report output" section for the full preamble text.
The summary then confirms that all composed endpoints are documented:

[source,asciidoc]
----
= Shadow API Report
:toc:
:toclevels: 2

Generated: ...

Scanned 3 endpoint(s) exposed by `@RestController` classes. 0 of them are not described in the OpenAPI documentation.

== Shadow APIs

None found. Every endpoint exposed by the scanned controllers is described in the OpenAPI documentation.
----
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
plugins {
id 'java'
alias(libs.plugins.shadow.api.detector)
}

java {
toolchain {
languageVersion = JavaLanguageVersion.of(21)
}
}

repositories {
mavenCentral()
}

dependencies {
implementation libs.spring.web
}

shadowApiDetector {
// The only property that must be set: the root OpenAPI document. Every other
// property already defaults correctly for this example's layout.
rootDocument = file('src/main/resources/openapi/openapi.yaml')
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.jvmargs=-Xmx8192m -Dfile.encoding=UTF-8

group=com.arc-e-tect
version = 0.0.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Generated by $ ./gradlew refreshVersionsCatalog

[plugins]

shadow-api-detector = { id = "com.arc-e-tect.shadow-api-detector", version.ref = "shadow-api-detector" }

[versions]

shadow-api-detector = "0.4.0"
spring-web = "7.0.8"

[libraries]

spring-web = { module = "org.springframework:spring-web", version.ref = "spring-web" }

Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading