Skip to content

Conversation

@neeme-praks-sympower
Copy link
Contributor

@neeme-praks-sympower neeme-praks-sympower commented Jan 5, 2026

Summary

Fixes a regression (#22609) by reverting the nested property placeholder syntax introduced in #22377 back to the simple ${api.base-path:<default>} syntax that worked in version 7.17.0.

Before (7.18.0 - broken):

@RequestMapping("${openapi.openAPIPetstore.base-path:${api.base-path:/v2}}")

After (this fix - same as 7.17.0):

@RequestMapping("${api.base-path:/v2}")

Problem

Spring's @RequestMapping annotation processing does not properly resolve nested ${outer:${inner:default}} property placeholder syntax. While the Kotlin string interpolation of $BASE_PATH works correctly at compile time (verified via javap), the nested placeholder structure causes Spring to fail to apply the base path at runtime.

This results in API endpoints being mounted at incorrect paths (e.g., /gateways/... instead of /api/v1/devices/gateways/...), causing 404 errors when clients call the expected URLs.

Setting properties explicitly in application.properties does not resolve the issue, confirming that Spring's @RequestMapping annotation processing doesn't support nested placeholder syntax.

Solution

Reverted to the simple property placeholder syntax from version 7.17.0:

@RequestMapping("${api.base-path:/v2}")

This:

  • Uses the OpenAPI spec's server URL as the default value (inlined at generation time)
  • Is fully backward compatible with 7.17.0 behavior
  • Properly resolves at runtime

Per-API Base Path Configuration

For users who need different base paths for different APIs (the feature that #22377 attempted to provide), this can be achieved programmatically using Spring's WebMvcConfigurer:

@Configuration
class ApiPathConfiguration : WebMvcConfigurer {

    @Value("\${my-petstore-api.base-path:/v2}")
    private lateinit var petstoreBasePath: String

    @Value("\${my-store-api.base-path:/v3}")
    private lateinit var storeBasePath: String

    override fun configurePathMatch(configurer: PathMatchConfigurer) {
        // Configure different base paths for different API controllers
        configurer.addPathPrefix(petstoreBasePath) { clazz ->
            clazz.packageName.contains("petstore")
        }
        configurer.addPathPrefix(storeBasePath) { clazz ->
            clazz.packageName.contains("store")
        }
    }
}

This approach:

  • Allows fully customizable property names
  • Supports multiple APIs with different base paths
  • Works reliably with Spring's property resolution
  • Can use package names, annotations, or any other criteria to match controllers

Files Changed

Templates

  • modules/openapi-generator/src/main/resources/kotlin-spring/api.mustache
  • modules/openapi-generator/src/main/resources/kotlin-spring/apiController.mustache
  • modules/openapi-generator/src/main/resources/kotlin-spring/apiInterface.mustache
  • modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-declarative-http-interface/apiInterface.mustache
  • modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/application.mustache

Tests

  • modules/openapi-generator/src/test/java/org/openapitools/codegen/kotlin/spring/KotlinSpringServerCodegenTest.java

Related Issues

Fixes #22609

Testing

  • Updated existing tests to verify the reverted pattern
  • All 3 affected tests pass:
    • testNoRequestMappingAnnotationController
    • testNoRequestMappingAnnotationApiInterface
    • generateHttpInterface

Technical Committee

cc @dr4ke616 (Kotlin Spring Boot)


Summary by cubic

Reverts Kotlin Spring @RequestMapping from nested property placeholders to the simple ${api.base-path:} so Spring resolves base paths correctly at runtime. Restores 7.17.0 behavior and prevents endpoints mounting at wrong paths.

  • Bug Fixes
    • Use @RequestMapping("${api.base-path:{{contextPath}}}") in Kotlin Spring and @HttpExchange("${api.base-path:{{contextPath}}}") in declarative HTTP interface templates.
    • Update tests to expect the simple placeholder; all passing.
    • Align sample controllers with the new syntax.

Written for commit c9ce72a. Summary will update on new commits.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 44 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-declarative-http-interface/apiInterface.mustache">

<violation number="1" location="modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-declarative-http-interface/apiInterface.mustache:54">
P2: The change removes the usage of `$BASE_PATH` but the import statement for `BASE_PATH` remains in the template (line 11-13 in file context). This will generate Kotlin files with unused imports, causing linting warnings. Consider removing the `BASE_PATH` import since it&#39;s no longer used in the `@HttpExchange` annotation.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@Picazsoo
Copy link
Contributor

Picazsoo commented Jan 6, 2026

Looks good to me. I once again apologize for introducing this troublesome regression.

@wing328
Copy link
Member

wing328 commented Jan 6, 2026

thanks for the PR

cc @karismann (2019/03) @Zomzog (2019/04) @andrewemery (2019/10) @4brunu (2019/11) @yutaka0m (2020/03) @stefankoppier (2022/06) @e5l (2024/10)

@wing328 wing328 added this to the 7.19.0 milestone Jan 6, 2026
@wing328 wing328 merged commit 753330d into OpenAPITools:master Jan 6, 2026
57 checks passed
@neeme-praks-sympower neeme-praks-sympower deleted the fix-nested-property branch January 7, 2026 22:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] [kotlin+jvm-spring-restclient] Base URLs regression

3 participants