Skip to content

Commit 0469e43

Browse files
committed
Merge branch 'master' into feature/add-enum-validation-for-pageable-paged-model
# Conflicts: # modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache # samples/server/petstore/kotlin-spring-sealed-interfaces/build.gradle.kts # samples/server/petstore/kotlin-springboot-3-no-response-entity/build.gradle.kts # samples/server/petstore/kotlin-springboot-3/build.gradle.kts # samples/server/petstore/kotlin-springboot-additionalproperties/build.gradle.kts # samples/server/petstore/kotlin-springboot-delegate-nodefaults/build.gradle.kts # samples/server/petstore/kotlin-springboot-integer-enum/build.gradle.kts # samples/server/petstore/kotlin-springboot-request-cookie/build.gradle.kts
2 parents faa1326 + e6c830e commit 0469e43

85 files changed

Lines changed: 572 additions & 237 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/samples-julia.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
runs-on: ubuntu-latest
1717
steps:
1818
- uses: actions/checkout@v5
19-
- uses: julia-actions/setup-julia@v2
19+
- uses: julia-actions/setup-julia@v3
2020
with:
2121
version: 1.8
2222
arch: x64

README.md

Lines changed: 42 additions & 39 deletions
Large diffs are not rendered by default.

docs/installation.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,14 @@ export JAVA_HOME=`/usr/libexec/java_home -v 1.11`
143143
export PATH=${JAVA_HOME}/bin:$PATH
144144
```
145145

146+
## JBang
147+
148+
> **Platform(s)**: Linux, macOS, Windows
149+
150+
Use [JBang](https://www.jbang.dev/) to retrieve and run the JAR file using Maven coordinates.
151+
152+
Run `jbang --java 11 org.openapitools:openapi-generator-cli:LATEST help` to show the usage.
153+
146154
## Bash Launcher Script
147155

148156
> **Platform(s)**: Linux, macOS, Windows (variable)

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractPhpCodegen.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,9 +781,46 @@ public String toEnumValue(String value, String datatype) {
781781
}
782782
}
783783

784+
/**
785+
* Builds the PHP expression for a backed enum case default (PHP 8.1+ {@code enum}).
786+
* <p>
787+
* The legacy {@code self::}{@code <datatype>_<CASE>} form came from class-constant style enums (#10273) and is
788+
* invalid when {@code datatype} is a namespaced class: {@code self::} only resolves constants on the current
789+
* class. Native enums must use {@code EnumType::CASE}.
790+
* <p>
791+
* Execution: {@code datatype} is produced upstream (e.g. {@link DefaultCodegen#updateCodegenPropertyEnum}) via
792+
* {@link #getTypeDeclaration(Schema)} for the referenced enum schema; {@code value} is the sanitized case name
793+
* from {@link #toEnumVarName}. When the enum class sits under {@link #modelPackage}, we emit only the short class
794+
* name plus {@code ::} so it matches sibling model references in generated files ({@code namespace} is
795+
* {@code modelPackage}; unqualified names resolve correctly). A fully qualified body without a leading
796+
* {@code \} would be resolved relative to the file namespace and is invalid PHP for defaults.
797+
*
798+
* @param value enum case name (e.g. {@code AVAILABLE})
799+
* @param datatype enum class as produced by {@link #getTypeDeclaration(Schema)} (may include {@code modelPackage})
800+
* @return PHP default expression for that case (e.g. {@code PetStatus::AVAILABLE})
801+
*/
784802
@Override
785803
public String toEnumDefaultValue(String value, String datatype) {
786-
return "self::" + datatype + "_" + value;
804+
return unqualifiedEnumClassForModelDefault(datatype) + "::" + value;
805+
}
806+
807+
/**
808+
* Strips {@link #modelPackage} from a declared enum class name so defaults use the same unqualified form as
809+
* property type hints in model templates.
810+
*
811+
* @param datatype enum class string from codegen (optional leading {@code \})
812+
* @return short class name if under {@code modelPackage}, otherwise the original {@code datatype}
813+
*/
814+
private String unqualifiedEnumClassForModelDefault(String datatype) {
815+
if (StringUtils.isBlank(datatype) || StringUtils.isBlank(modelPackage)) {
816+
return datatype;
817+
}
818+
String normalized = datatype.charAt(0) == '\\' ? datatype.substring(1) : datatype;
819+
String prefix = modelPackage + "\\";
820+
if (normalized.startsWith(prefix)) {
821+
return normalized.substring(prefix.length());
822+
}
823+
return datatype;
787824
}
788825

789826
@Override

modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/anyof_model.mustache

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
238238
/**
239239
* Set the instance that matches the anyOf child schema, check
240240
* the instance parameter is valid against the anyOf child schemas:
241-
* {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}
241+
* {{#anyOf}}{{.}}{{^-last}}, {{/-last}}{{/anyOf}}
242242
*
243243
* It could be an instance of the 'anyOf' schemas.
244244
*/
@@ -276,9 +276,9 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
276276

277277
/**
278278
* Get the actual instance, which can be the following:
279-
* {{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}}
279+
* {{#anyOf}}{{.}}{{^-last}}, {{/-last}}{{/anyOf}}
280280
*
281-
* @return The actual instance ({{#anyOf}}{{{.}}}{{^-last}}, {{/-last}}{{/anyOf}})
281+
* @return The actual instance ({{#anyOf}}{{.}}{{^-last}}, {{/-last}}{{/anyOf}})
282282
*/
283283
@SuppressWarnings("unchecked")
284284
@Override
@@ -290,11 +290,11 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
290290
{{#anyOf}}
291291
{{^vendorExtensions.x-duplicated-data-type-ignoring-erasure}}
292292
/**
293-
* Get the actual instance of `{{{dataType}}}`. If the actual instance is not `{{{dataType}}}`,
293+
* Get the actual instance of `{{dataType}}`. If the actual instance is not `{{dataType}}`,
294294
* the ClassCastException will be thrown.
295295
*
296-
* @return The actual instance of `{{{dataType}}}`
297-
* @throws ClassCastException if the instance is not `{{{dataType}}}`
296+
* @return The actual instance of `{{dataType}}`
297+
* @throws ClassCastException if the instance is not `{{dataType}}`
298298
*/
299299
public {{{dataType}}} get{{#sanitizeDataType}}{{{dataType}}}{{/sanitizeDataType}}() throws ClassCastException {
300300
return ({{{dataType}}})super.getActualInstance();

modules/openapi-generator/src/main/resources/Java/libraries/okhttp-gson/oneof_model.mustache

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
316316
/**
317317
* Set the instance that matches the oneOf child schema, check
318318
* the instance parameter is valid against the oneOf child schemas:
319-
* {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}
319+
* {{#oneOf}}{{.}}{{^-last}}, {{/-last}}{{/oneOf}}
320320
*
321321
* It could be an instance of the 'oneOf' schemas.
322322
*/
@@ -354,9 +354,9 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
354354

355355
/**
356356
* Get the actual instance, which can be the following:
357-
* {{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}}
357+
* {{#oneOf}}{{.}}{{^-last}}, {{/-last}}{{/oneOf}}
358358
*
359-
* @return The actual instance ({{#oneOf}}{{{.}}}{{^-last}}, {{/-last}}{{/oneOf}})
359+
* @return The actual instance ({{#oneOf}}{{.}}{{^-last}}, {{/-last}}{{/oneOf}})
360360
*/
361361
@SuppressWarnings("unchecked")
362362
@Override
@@ -368,12 +368,13 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
368368
{{#oneOf}}
369369
{{^vendorExtensions.x-duplicated-data-type-ignoring-erasure}}
370370
/**
371-
* Get the actual instance of `{{{dataType}}}`. If the actual instance is not `{{{dataType}}}`,
371+
* Get the actual instance of `{{dataType}}`. If the actual instance is not `{{dataType}}`,
372372
* the ClassCastException will be thrown.
373373
*
374-
* @return The actual instance of `{{{dataType}}}`
375-
* @throws ClassCastException if the instance is not `{{{dataType}}}`
374+
* @return The actual instance of `{{dataType}}`
375+
* @throws ClassCastException if the instance is not `{{dataType}}`
376376
*/
377+
@SuppressWarnings("unchecked")
377378
public {{{dataType}}} get{{#sanitizeDataType}}{{{dataType}}}{{/sanitizeDataType}}() throws ClassCastException {
378379
return ({{{dataType}}})super.getActualInstance();
379380
}

modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-cloud/pom-sb3.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<dependency>
5959
<groupId>org.springframework.cloud</groupId>
6060
<artifactId>spring-cloud-starter-parent</artifactId>
61-
<version>2023.0.0</version>
61+
<version>2023.0.6</version>
6262
<type>pom</type>
6363
<scope>import</scope>
6464
</dependency>

modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-boot/buildGradle-sb3-Kts.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ plugins {
2525
id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
2626
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
2727
id("org.springframework.boot") version "3.3.13"
28-
id("io.spring.dependency-management") version "1.0.14.RELEASE"
28+
id("io.spring.dependency-management") version "1.1.7"
2929
}
3030

3131
dependencies {

modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/buildGradle-sb3-Kts.mustache

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ plugins {
1818
id("org.jetbrains.kotlin.jvm") version kotlinVersion
1919
id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
2020
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
21-
id("org.springframework.boot") version "3.0.2"
22-
id("io.spring.dependency-management") version "1.0.14.RELEASE"
21+
id("org.springframework.boot") version "3.3.13"
22+
id("io.spring.dependency-management") version "1.1.7"
2323
}
2424

2525
tasks.getByName("bootJar") {
@@ -32,7 +32,7 @@ tasks.getByName("jar") {
3232

3333
dependencyManagement {
3434
imports {
35-
mavenBom("org.springframework.cloud:spring-cloud-dependencies:2021.0.5")
35+
mavenBom("org.springframework.cloud:spring-cloud-dependencies:2023.0.6")
3636
}
3737
}
3838

@@ -58,7 +58,7 @@ dependencies {
5858
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
5959

6060
implementation("org.springframework.cloud:spring-cloud-starter-openfeign"){{#hasAuthMethods}}
61-
implementation("org.springframework.cloud:spring-cloud-starter-oauth2:2.2.5.RELEASE"){{/hasAuthMethods}}
61+
implementation("org.springframework.boot:spring-boot-starter-oauth2-client"){{/hasAuthMethods}}
6262

6363
{{#useBeanValidation}}
6464
implementation("jakarta.validation:jakarta.validation-api"){{/useBeanValidation}}

modules/openapi-generator/src/main/resources/kotlin-spring/libraries/spring-cloud/clientConfiguration.mustache

Lines changed: 79 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,14 @@ import feign.auth.BasicAuthRequestInterceptor
88
import org.springframework.beans.factory.annotation.Value
99
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
1010
{{/-first}}
11-
{{^useSpringBoot4}}
12-
{{#isOAuth}}
13-
import org.springframework.boot.context.properties.ConfigurationProperties
14-
{{/isOAuth}}
15-
{{/useSpringBoot4}}
11+
{{^useSpringBoot4}}{{^useSpringBoot3}}{{#isOAuth}}import org.springframework.boot.context.properties.ConfigurationProperties{{/isOAuth}}{{/useSpringBoot3}}{{/useSpringBoot4}}
1612
{{/authMethods}}
17-
{{^useSpringBoot4}}
18-
import org.springframework.boot.context.properties.EnableConfigurationProperties
19-
{{/useSpringBoot4}}
13+
{{^useSpringBoot4}}{{^useSpringBoot3}}import org.springframework.boot.context.properties.EnableConfigurationProperties{{/useSpringBoot3}}{{/useSpringBoot4}}
2014
{{#hasAuthMethods}}
2115
import org.springframework.context.annotation.Bean
2216
{{/hasAuthMethods}}
2317
import org.springframework.context.annotation.Configuration
24-
{{^useSpringBoot4}}
18+
{{^useSpringBoot4}}{{^useSpringBoot3}}
2519
{{#authMethods}}
2620
{{#isOAuth}}
2721
import org.springframework.cloud.openfeign.security.OAuth2FeignRequestInterceptor
@@ -41,7 +35,24 @@ import org.springframework.security.oauth2.client.token.grant.password.ResourceO
4135
{{/isPassword}}
4236
{{/isOAuth}}
4337
{{/authMethods}}
44-
{{/useSpringBoot4}}
38+
{{/useSpringBoot3}}{{/useSpringBoot4}}
39+
{{#useSpringBoot3}}
40+
{{#hasOAuthMethods}}
41+
import org.springframework.security.authentication.AnonymousAuthenticationToken
42+
import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager
43+
import org.springframework.security.oauth2.client.OAuth2AuthorizeRequest
44+
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager
45+
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService
46+
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
47+
import org.springframework.security.oauth2.core.OAuth2AuthenticationException
48+
import org.springframework.security.oauth2.core.OAuth2AccessToken
49+
import org.springframework.security.core.authority.AuthorityUtils
50+
import org.springframework.http.HttpHeaders
51+
52+
import feign.RequestInterceptor
53+
import feign.RequestTemplate
54+
{{/hasOAuthMethods}}
55+
{{/useSpringBoot3}}
4556
{{#useSpringBoot4}}
4657
{{#hasOAuthMethods}}
4758
import org.springframework.security.authentication.AnonymousAuthenticationToken
@@ -60,10 +71,8 @@ import feign.RequestTemplate
6071
{{/hasOAuthMethods}}
6172
{{/useSpringBoot4}}
6273

63-
@Configuration
64-
{{^useSpringBoot4}}
65-
@EnableConfigurationProperties
66-
{{/useSpringBoot4}}
74+
@Configuration{{^useSpringBoot4}}{{^useSpringBoot3}}
75+
@EnableConfigurationProperties{{/useSpringBoot3}}{{/useSpringBoot4}}
6776
class ClientConfiguration {
6877
6978
{{#authMethods}}
@@ -93,7 +102,7 @@ class ClientConfiguration {
93102

94103
{{/isApiKey}}
95104
{{#isOAuth}}
96-
{{^useSpringBoot4}}
105+
{{^useSpringBoot4}}{{^useSpringBoot3}}
97106
@Bean
98107
@ConditionalOnProperty("{{#lambda.lowercase}}{{{title}}}{{/lambda.lowercase}}.security.{{{name}}}.client-id")
99108
fun {{#lambda.camelcase}}{{{name}}}{{/lambda.camelcase}}RequestInterceptor(oAuth2ClientContext: OAuth2ClientContext): OAuth2FeignRequestInterceptor {
@@ -151,7 +160,29 @@ class ClientConfiguration {
151160
}
152161

153162
{{/isImplicit}}
154-
{{/useSpringBoot4}}
163+
{{/useSpringBoot3}}{{/useSpringBoot4}}
164+
{{#useSpringBoot3}}
165+
@Bean
166+
@ConditionalOnProperty(prefix = "spring.security.oauth2.client.registration.{{{name}}}{{#lambda.pascalcase}}{{{flow}}}{{/lambda.pascalcase}}", name = ["enabled"], havingValue = "true")
167+
fun {{{flow}}}OAuth2RequestInterceptor({{{flow}}}AuthorizedClientManager: OAuth2AuthorizedClientManager): OAuth2RequestInterceptor {
168+
return OAuth2RequestInterceptor(
169+
OAuth2AuthorizeRequest.withClientRegistrationId("{{{name}}}{{#lambda.pascalcase}}{{{flow}}}{{/lambda.pascalcase}}")
170+
.principal(AnonymousAuthenticationToken(CLIENT_PRINCIPAL_{{#lambda.uppercase}}{{{flow}}}{{/lambda.uppercase}}, CLIENT_PRINCIPAL_{{#lambda.uppercase}}{{{flow}}}{{/lambda.uppercase}}, AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS")))
171+
.build(),
172+
{{{flow}}}AuthorizedClientManager
173+
)
174+
}
175+
176+
@Bean
177+
@ConditionalOnProperty(prefix = "spring.security.oauth2.client.registration.{{{name}}}{{#lambda.pascalcase}}{{{flow}}}{{/lambda.pascalcase}}", name = ["enabled"], havingValue = "true")
178+
fun {{{flow}}}AuthorizedClientManager(
179+
clientRegistrationRepository: ClientRegistrationRepository,
180+
authorizedClientService: OAuth2AuthorizedClientService
181+
): OAuth2AuthorizedClientManager {
182+
return AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService)
183+
}
184+
185+
{{/useSpringBoot3}}
155186
{{#useSpringBoot4}}
156187
@Bean
157188
@ConditionalOnProperty(prefix = "spring.security.oauth2.client.registration.{{{name}}}{{#lambda.pascalcase}}{{{flow}}}{{/lambda.pascalcase}}", name = ["enabled"], havingValue = "true")
@@ -176,6 +207,38 @@ class ClientConfiguration {
176207
{{/useSpringBoot4}}
177208
{{/isOAuth}}
178209
{{/authMethods}}
210+
{{#useSpringBoot3}}
211+
{{#hasOAuthMethods}}
212+
class OAuth2RequestInterceptor(
213+
private val oAuth2AuthorizeRequest: OAuth2AuthorizeRequest,
214+
private val oAuth2AuthorizedClientManager: OAuth2AuthorizedClientManager
215+
) : RequestInterceptor {
216+
217+
override fun apply(template: RequestTemplate) {
218+
template.header(HttpHeaders.AUTHORIZATION, getBearerToken())
219+
}
220+
221+
fun getAccessToken(): OAuth2AccessToken {
222+
val authorizedClient = oAuth2AuthorizedClientManager.authorize(oAuth2AuthorizeRequest)
223+
?: throw OAuth2AuthenticationException("Client failed to authenticate")
224+
return authorizedClient.accessToken
225+
}
226+
227+
fun getBearerToken(): String {
228+
val accessToken = getAccessToken()
229+
return String.format(java.util.Locale.ROOT, "%s %s", accessToken.tokenType?.value, accessToken.tokenValue)
230+
}
231+
}
232+
233+
companion object {
234+
{{#authMethods}}
235+
{{#isOAuth}}
236+
private const val CLIENT_PRINCIPAL_{{#lambda.uppercase}}{{{flow}}}{{/lambda.uppercase}} = "oauth2FeignClient"
237+
{{/isOAuth}}
238+
{{/authMethods}}
239+
}
240+
{{/hasOAuthMethods}}
241+
{{/useSpringBoot3}}
179242
{{#useSpringBoot4}}
180243
{{#hasOAuthMethods}}
181244
class OAuth2RequestInterceptor(

0 commit comments

Comments
 (0)