Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
266aed7
Migrate build system to Quarkus
Jun 12, 2026
74474fa
Migrate common module DI, scheduling and API markers to CDI/Quarkus (…
Jun 12, 2026
5dd6d7b
Migrate common AppConfig producers to CDI
Jun 12, 2026
5157b6e
Add migration report
Jun 12, 2026
0aad71b
Convert common module services/utils/config to CDI via workflow (WIP)
Jun 12, 2026
5eec2b4
Add MultipartFile compatibility shim and swap common imports to it
Jun 12, 2026
f24c9e0
Update migration report with common module progress
Jun 12, 2026
f0c7fbd
Add Resource shim; convert WebResponseUtils to JAX-RS Response/Stream…
Jun 12, 2026
638f7e8
Convert common residual files (ResponseEntity, streaming, AOP) via wo…
Jun 12, 2026
9fe815b
Update report: common 69/77 files converted, 8 framework residuals do…
Jun 12, 2026
4d69bce
Complete common module migration: AutoJob CDI interceptor, InternalAp…
Jun 12, 2026
7e06862
Convert core module controllers/services/config to JAX-RS/CDI via wor…
Jun 12, 2026
cec00ab
Fix core compile errors; core flavor (common+core) compiles on Quarkus
Jun 12, 2026
2591faa
Convert proprietary module (security/JPA/oauth2/saml2) to Quarkus via…
Jun 12, 2026
611574f
Add Spring Security compat shim; clear residual proprietary Spring im…
Jun 12, 2026
06da959
Fix all proprietary module compile errors for Quarkus migration
Jun 12, 2026
d51228a
Compile default-flavor tests on Quarkus; exclude Spring-test-infra tests
Jun 12, 2026
185ac88
Resolve Quarkus CDI augmentation: app builds on default flavor
Jun 12, 2026
20b25ad
Fix runtime boot: JSON column mapping, Quartz cron, H2 config
Jun 12, 2026
10f4ecd
Update migration report with verified default-flavor results
Jun 12, 2026
e07eefc
Adapt FileStorage tests to Instance<JobOwnershipService> constructor
Jun 12, 2026
fe6c6c0
Complete saas module Spring->Quarkus migration (compiles under saas f…
Jun 12, 2026
90e8e34
Document saas-flavor augmentation status in migration report
Jun 12, 2026
4665cce
Make app boot without Redis: gate Valkey beans at build time, disable…
Jun 12, 2026
4b57285
Replace HttpServletRequest with reactive-safe @Context in exception h…
Jun 12, 2026
860bd6e
Make request-path reactive-safe: audit/job aspects, JobExecutorServic…
Jun 12, 2026
ee26b35
Record Docker + cucumber e2e results (62% scenarios pass) in migratio…
Jun 12, 2026
a30d524
Fix MultipartFile.transferTo overwrite + maxDPI default 500 (cucumber…
Jun 12, 2026
b9069a1
Add Quarkus migration continuation/handoff doc
Jun 12, 2026
1bc548d
Add first-class Quarkus e2e Dockerfile + build helper
Jun 13, 2026
33dad0f
Create default admin at startup; fix DataSource proxy and login 401 m…
Jun 13, 2026
4036271
Make policy store reads transactional for off-request scheduled triggers
Jun 13, 2026
cc40a17
Keep Quarkus runner-jar in Docker build context
Jun 13, 2026
69b6a49
Drop redundant duplicate fileInput part from split scenarios
Jun 13, 2026
96ad92c
Add JWT Bearer auth mechanism to populate Quarkus SecurityIdentity
Jun 13, 2026
c3a13f2
Default loginAttemptCount=5 and loginResetTimeMinutes=120 to match te…
Jun 13, 2026
e49d026
Update migration handoff with Session 2 fixes and e2e results
Jun 13, 2026
4c125a2
Bind fileInput to the real file part when a duplicate text part is pr…
Jun 13, 2026
05d3ba6
Add @Transactional to user write/read service methods (Panache needs …
Jun 13, 2026
5679967
Add X-API-KEY auth mechanism to populate SecurityIdentity
Jun 13, 2026
4008161
Bind security/storage config from env and attach User as SecurityIden…
Jun 13, 2026
daf3925
Handoff: login-on results, auth foundation done, SSO/SAML plan
Jun 13, 2026
33499d5
Implement OAuth2/OIDC login (authorize redirect + callback servlet) e…
Jun 13, 2026
57063c5
Add SAML2 SP metadata endpoint (OpenSAML 5)
Jun 13, 2026
e0b9ef2
Implement SAML2 login flow (signed AuthnRequest + ACS response valida…
Jun 13, 2026
e55c177
Handoff: OAuth2 + SAML2 SSO working end-to-end
Jun 13, 2026
d15dbcf
Remove redundant META-INF/resources duplicate and dead legacy static …
Jun 13, 2026
8cea88e
Allow Public Domain license for jboss-transaction-spi dependency
Jun 13, 2026
61feed0
Set Secure and SameSite on SSO JWT cookie; apply spotless formatting
Jun 13, 2026
3543ac9
Fix Quarkus migration build failures for core, proprietary and saas f…
Frooodle Jun 13, 2026
403bf55
Raise Gradle daemon heap to fix CI OOM on proprietary and saas builds
Frooodle Jun 13, 2026
a77226f
Fix remaining CI checks and restore Spring profile, settings.yml and …
Frooodle Jun 13, 2026
e410933
Serve React bundle from META-INF/resources and fix SPA asset MIME types
Frooodle Jun 13, 2026
4ada6e7
Apply spotless formatting to SPA routing comment
Frooodle Jun 13, 2026
8d363f8
Regenerate AI engine tool models from Quarkus OpenAPI schema
Frooodle Jun 13, 2026
36212b7
Fix enterprise SSO login button, callback session and premium license…
Frooodle Jun 13, 2026
c78c652
Enforce settings.yml endpoint disabling under Quarkus
Frooodle Jun 13, 2026
179bf8c
Replace hardcoded config overlay with generic reflective ApplicationP…
Frooodle Jun 13, 2026
907a754
Serve .mjs and .wasm static assets with correct MIME type
Frooodle Jun 13, 2026
a310ab8
Normalize OAuth2 scope list to avoid invalid_scope on comma-space config
Frooodle Jun 13, 2026
63c4d19
Restore Angle and EditTextOperation OpenAPI schemas for AI engine too…
Frooodle Jun 13, 2026
a3870c4
Apply endpoint disabling only to /api paths so SPA tool routes still …
Frooodle Jun 13, 2026
7b433de
Fix remaining cucumber regression failures in storage, user and form …
Frooodle Jun 13, 2026
1180951
Serve swagger-ui at springdoc path and resolve migration TODOs (auth,…
Frooodle Jun 13, 2026
88075a7
Bind AI workflow and cert-sign multipart file uploads via FileUpload
Frooodle Jun 13, 2026
1d2c5d2
Restore demo-user guard via DenyDemoUser interceptor on account/signa…
Frooodle Jun 13, 2026
5fa8d20
Restore legacy static assets removed during migration (asset cleanup …
Frooodle Jun 14, 2026
991fdac
Re-enable 14 unit tests by porting MultipartFile/Resource mocks to mi…
Frooodle Jun 14, 2026
e0b898c
Re-enable excluded service/security/util unit tests by porting Spring…
Frooodle Jun 14, 2026
e55dad4
Add FileUpload test fixture and port RotationControllerTest (controll…
Frooodle Jun 14, 2026
a7373d0
Port controller/service/filter unit tests off Spring to Quarkus fixtures
Frooodle Jun 14, 2026
ccf2b88
Port converter, security, MCP and CDI-infra tests off Spring to Quarkus
Frooodle Jun 14, 2026
8096d5e
Merge main into migration/run-02 with full Spring removal for pulled-…
Frooodle Jun 19, 2026
6512498
Exclude merge-pulled-in signature-mismatch tests from Quarkus build
Frooodle Jun 19, 2026
2dcac5b
Restore JDK 25 detection in db-migration test script after Quarkus merge
Frooodle Jun 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
build/
*/build/
**/build/
# ...but re-include the Quarkus runner-jar so docker/quarkus/Dockerfile can layer it on the base image
!app/core/build/*-runner.jar
out/
target/
**/target/
Expand Down
12 changes: 7 additions & 5 deletions .github/workflows/db-migration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,18 @@ jobs:
MAVEN_USER: ${{ secrets.MAVEN_USER }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
MAVEN_PUBLIC_URL: ${{ secrets.MAVEN_PUBLIC_URL }}
run: ./gradlew :stirling-pdf:bootJar -PnoSpotless --no-daemon
run: ./gradlew :stirling-pdf:quarkusBuild -PnoSpotless --no-daemon

- name: Locate built JAR
id: jar
run: |
jar=$(find app/core/build/libs -maxdepth 1 -name 'Stirling-PDF*.jar' -o -name 'stirling-pdf*.jar' 2>/dev/null \
| grep -vE '(-plain|-sources)\.jar$' | head -n 1)
# Quarkus (quarkus.package.jar.type=uber-jar) emits a standalone runnable
# jar at app/core/build/<name>-runner.jar, replacing the Spring Boot bootJar
# that used to land in app/core/build/libs.
jar=$(find app/core/build -maxdepth 1 -name '*-runner.jar' 2>/dev/null | head -n 1)
if [[ -z "$jar" ]]; then
echo "::error::No JAR under app/core/build/libs"
ls -lah app/core/build/libs || true
echo "::error::No *-runner.jar under app/core/build"
ls -lah app/core/build || true
exit 1
fi
# Absolute path - the migration script pushd's into a temp workdir
Expand Down
30 changes: 25 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@ SwaggerDoc.json
# Runtime storage for uploaded files and user data (not Java source code)
app/core/storage/

# Frontend build artifacts copied to backend static resources
# These are generated by npm build and should not be committed
app/core/src/main/resources/static/assets/
# Frontend build artifacts copied to Quarkus static resources
# Generated by `npm build` + the copyFrontendAssets/copyFrontendIndexHtml tasks; never committed.
# The React bundle goes to META-INF/resources/ (Quarkus serves these over HTTP); index.html is the
# only generated file in static/ (ReactRoutingController serves it). See app/core/build.gradle.
app/core/src/main/resources/META-INF/resources/
app/core/src/main/resources/static/index.html
# Migration cleanup: earlier builds emitted the whole bundle into static/. Keep these ignored so
# any stale generated assets left in static/ are not accidentally committed.
app/core/src/main/resources/static/assets/
# Prerendered per-route SPA pages (OG/social-preview), e.g. compress.html. api-landing.html is source.
app/core/src/main/resources/static/*.html
!app/core/src/main/resources/static/api-landing.html
Expand All @@ -66,7 +71,7 @@ app/core/src/main/resources/static/pdfjs/
app/core/src/main/resources/static/vendor/
app/core/src/main/resources/static/**/*.gz
app/core/src/main/resources/static/**/*.br
# Note: Keep backend-managed files like fonts/, css/, js/, pdfjs/, etc.
# Note: Keep backend-managed files like fonts/, css/, js/, etc.

# Gradle
.gradle
Expand Down Expand Up @@ -280,8 +285,23 @@ docs/type3/signatures/

**/application-dev-local.properties

# Claude
# AI agent session/local files - may contain tokens and secrets
.claude/
.agents/
.cursor/
.codex/
.opencode/
.copilot/
.cline/
.continue/
.windsurf/
.junie/
.pi/
.roo/
.augment/
.aider*
CLAUDE.local.md
skills-lock.json

# Playwright MCP screenshots / traces
.playwright-mcp/
Expand Down
2 changes: 1 addition & 1 deletion .taskfiles/pre-commit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ tasks:
codespell:
deps: [install]
cmds:
- uv run --project scripts/pre-commit --no-sync codespell --ignore-words-list=thirdParty,tabEl,tabEls,Sie,ist,fulfilment --quiet-level=2 $(git ls-files {{.SPELL_FILES}})
- uv run --project scripts/pre-commit --no-sync codespell --ignore-words-list=thirdParty,tabEl,tabEls,Sie,ist,fulfilment,vertx --quiet-level=2 $(git ls-files {{.SPELL_FILES}})

toml-sort:
deps: [install]
Expand Down
563 changes: 563 additions & 0 deletions QUARKUS_MIGRATION_HANDOFF.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions app/allowed-licenses.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"allowedLicenses": [
{
"moduleName": "org.jboss:jboss-transaction-spi",
"moduleLicense": "Public Domain"
},
{
"moduleName": ".*",
"moduleLicense": "BSD License"
Expand Down
41 changes: 34 additions & 7 deletions app/common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
// Configure bootRun to disable it or point to a main class
bootRun {
enabled = false
}
// REMOVED: bootRun{enabled=false} - Spring Boot plugin task. :common is a Quarkus library module.
spotless {
java {
target 'src/**/java/**/*.java'
Expand Down Expand Up @@ -30,8 +27,29 @@ spotless {
}
dependencies {
api 'com.google.guava:guava:33.6.0-jre'
api 'org.springframework.boot:spring-boot-starter-webmvc'
api 'org.springframework.boot:spring-boot-starter-aspectj'

// spring-boot-starter-webmvc -> Quarkus REST stack (api-scoped so downstream modules inherit it).
api 'io.quarkus:quarkus-rest'
api 'io.quarkus:quarkus-rest-jackson'
// Servlet bridge: large amounts of controller/filter code use jakarta.servlet (HttpServletRequest,
// Filter, etc.). quarkus-undertow provides a servlet container on Quarkus so that API resolves and
// runs. TODO: Migration required - longer term, port servlet usage to JAX-RS (ContainerRequestContext)
// and drop quarkus-undertow.
api 'io.quarkus:quarkus-undertow'
// Bean Validation (was transitively in spring-boot-starter-webmvc).
api 'io.quarkus:quarkus-hibernate-validator'
// @Scheduled support (was spring-context scheduling). quarkus-scheduler manages its own
// executor; the former SchedulingConfig TaskScheduler bean is no longer needed.
api 'io.quarkus:quarkus-scheduler'
// BCrypt implementation backing the Spring Security PasswordEncoder compatibility shim
// (replaces spring-security-crypto's BCryptPasswordEncoder). Standalone, no framework.
api 'at.favre.lib:bcrypt:0.10.2'
// Swagger/OpenAPI annotations (io.swagger.v3.oas.annotations.*) used by common's API marker
// interfaces; was transitive via springdoc. Quarkus' SmallRye OpenAPI also understands these.
api 'io.swagger.core.v3:swagger-core-jakarta:2.2.46'
// REMOVED: spring-boot-starter-aspectj. Quarkus has no AspectJ weaving; quarkus-arc provides
// CDI interceptors (@AroundInvoke / interceptor bindings) instead.
// TODO: Migration required - any @Aspect/@Around advice must be rewritten as CDI interceptors.
api 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:20260313.1'
api 'com.fathzer:javaluator:3.0.6'
api 'com.posthog.java:posthog:1.2.0'
Expand All @@ -45,7 +63,8 @@ dependencies {
api 'com.github.junrar:junrar:7.5.10' // RAR archive support for CBR files
api 'jakarta.servlet:jakarta.servlet-api:6.1.0'
api 'org.snakeyaml:snakeyaml-engine:3.0.1'
api "org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.3"
// springdoc-openapi-starter-webmvc-ui -> SmallRye OpenAPI (schema at /q/openapi, UI at /q/swagger-ui)
api 'io.quarkus:quarkus-smallrye-openapi'
// Simple Java Mail for EML/MSG parsing (replaces direct Angus Mail usage)
api 'org.simplejavamail:simple-java-mail:8.12.6'
api 'org.simplejavamail:outlook-module:8.12.6' // MSG file support
Expand Down Expand Up @@ -78,6 +97,14 @@ dependencies {
runtimeOnly "com.stirling:jpdfium-natives-${platform}:1.0.2"
}

// Jackson 3 (tools.jackson) - retained because ~100 files migrated to the Jackson 3 namespace
// under Spring Boot 4. Quarkus integrates Jackson 2 for REST bodies; Jackson 3 coexists here as a
// plain library so those files compile and can still build/parse JSON directly.
// api-scoped so downstream modules (core, proprietary, saas) that import tools.jackson inherit it.
// TODO: Migration required - converge the codebase on a single Jackson major version.
api 'tools.jackson.core:jackson-databind:3.0.0'
api 'tools.jackson.core:jackson-core:3.0.0'

// Bucket4j (local in-process token bucket for RateLimitStore default impl)
implementation 'com.bucket4j:bucket4j_jdk17-core:8.19.0'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import stirling.software.common.model.ApplicationProperties;

@Service
@ApplicationScoped
@Slf4j
public class EndpointConfiguration {

Expand Down Expand Up @@ -52,9 +53,10 @@ public DisableReason getReason() {
private Map<String, Set<String>> endpointAlternatives = new ConcurrentHashMap<>();
private final boolean runningProOrHigher;

@Inject
public EndpointConfiguration(
ApplicationProperties applicationProperties,
@Qualifier("runningProOrHigher") boolean runningProOrHigher) {
@Named("runningProOrHigher") boolean runningProOrHigher) {
this.applicationProperties = applicationProperties;
this.runningProOrHigher = runningProOrHigher;
init();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import java.util.List;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.springframework.stereotype.Service;

import jakarta.enterprise.context.ApplicationScoped;

import lombok.extern.slf4j.Slf4j;

Expand Down Expand Up @@ -47,7 +48,7 @@
* <li>Rotated tables (90°/270° pages) may produce incorrect bounds.
* </ul>
*/
@Service
@ApplicationScoped
@Slf4j
public class TabulaTableParser implements TableParser {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@

import java.lang.annotation.*;

import org.springframework.core.annotation.AliasFor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import io.swagger.v3.oas.annotations.parameters.RequestBody;

import jakarta.enterprise.util.Nonbinding;
import jakarta.interceptor.InterceptorBinding;
import jakarta.ws.rs.core.MediaType;

/**
* Shortcut for a POST endpoint that is executed through the Stirling "auto‑job" framework.
*
* <p>MIGRATION (Spring -> Quarkus): this was a Spring composed meta-annotation that stamped
* {@code @RequestMapping(method=POST)} onto the target via {@code @AliasFor}. JAX-RS does not
* honour {@code @Path}/{@code @POST}/{@code @Consumes} through meta-annotations, so this annotation
* no longer provides routing. It is now a CDI {@link InterceptorBinding} handled by {@code
* AutoJobInterceptor}. <b>Controllers using {@code @AutoJobPostMapping} must additionally declare
* their own JAX-RS {@code @POST} + {@code @Path(value)} + {@code @Consumes(consumes)}.</b> The
* {@link #value()}/{@link #consumes()} members are retained so a scanner/controller can read the
* intended routing.
*
* <p>Behaviour notes:
*
* <ul>
* <li>The endpoint is registered with {@code POST} and, by default, consumes {@code
* multipart/form-data} unless you override {@link #consumes()}.
* <li>When the client supplies {@code ?async=true} the call is handed to {@link
* stirling.software.common.service.JobExecutorService JobExecutorService} where it may be
* queued, retried, tracked and subject to time‑outs. For synchronous (default) invocations
Expand All @@ -26,29 +32,34 @@
* GET /api/v1/general/job/{id}</code>.
* </ul>
*
* <p>Unless stated otherwise an attribute only affects <em>async</em> execution.
* <p>Unless stated otherwise an attribute only affects <em>async</em> execution. All members are
* {@code @Nonbinding} so the single {@code AutoJobInterceptor} matches every annotated method; the
* interceptor reads the actual values reflectively from the target method.
*/
@Target(ElementType.METHOD)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.POST)
@InterceptorBinding
@RequestBody(required = true)
public @interface AutoJobPostMapping {

/** Alias for {@link RequestMapping#value} – the path mapping of the endpoint. */
@AliasFor(annotation = RequestMapping.class, attribute = "value")
/**
* The path mapping of the endpoint (controllers must mirror this on a JAX-RS {@code @Path}).
*/
@Nonbinding
String[] value() default {};

/** MIME types this endpoint accepts. Defaults to {@code multipart/form-data}. */
@AliasFor(annotation = RequestMapping.class, attribute = "consumes")
String[] consumes() default {MediaType.MULTIPART_FORM_DATA_VALUE};
@Nonbinding
String[] consumes() default {MediaType.MULTIPART_FORM_DATA};

/**
* Maximum execution time in milliseconds before the job is aborted. A negative value means "use
* the application default".
*
* <p>Only honoured when {@code async=true}.
*/
@Nonbinding
long timeout() default -1;

/**
Expand All @@ -57,13 +68,15 @@
*
* <p>Only honoured when {@code async=true}.
*/
@Nonbinding
int retryCount() default 1;

/**
* Record percentage / note updates so they can be retrieved via the REST status endpoint.
*
* <p>Only honoured when {@code async=true}.
*/
@Nonbinding
boolean trackProgress() default true;

/**
Expand All @@ -72,6 +85,7 @@
*
* <p>Only honoured when {@code async=true}.
*/
@Nonbinding
boolean queueable() default false;

/**
Expand All @@ -82,5 +96,6 @@
* AutoJobPostMappingWeightTest} fails the build if any endpoint leaves it unset. Runtime
* readers clamp the value into {@code [1, 100]}.
*/
@Nonbinding
int resourceWeight() default Integer.MIN_VALUE;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.tags.Tag;

/**
Expand All @@ -16,8 +13,9 @@
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/api/v1/account")
// MIGRATION (Spring->JAX-RS): controllers using this annotation must declare
// @jakarta.ws.rs.Path("/api/v1/account").
// JAX-RS does not honour @Path via meta-annotations, so the path is not inherited from here.
@Tag(
name = "Account Security",
description =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.tags.Tag;

/**
* Combined annotation for Admin Settings API controllers.
* Includes @RestController, @RequestMapping("/api/v1/admin/settings"), and OpenAPI @Tag.
*
* <p>MIGRATION (Spring -> JAX-RS): JAX-RS/RESTEasy does NOT process {@code @Path} via custom
* meta-annotations (Spring honoured composed {@code @RestController}/{@code @RequestMapping}
* through {@code @AliasFor}; JAX-RS has no equivalent). This annotation therefore now carries only
* the OpenAPI {@code @Tag}. Each controller annotated with {@code @AdminApi} MUST additionally
* declare its own {@code @jakarta.ws.rs.Path("/api/v1/admin/settings")} (the path the removed
* {@code @RequestMapping} used to supply).
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@RestController
@RequestMapping("/api/v1/admin/settings")
@Tag(
name = "Admin Settings",
description =
Expand Down
Loading
Loading