3939import java .util .Map ;
4040import java .util .function .Consumer ;
4141import java .util .function .Function ;
42+ import java .util .regex .Matcher ;
43+ import java .util .regex .Pattern ;
4244import java .util .stream .Collectors ;
4345import java .util .stream .Stream ;
4446
@@ -3831,7 +3833,7 @@ public void customPageableSchemaNotOverridden_issue13052() throws Exception {
38313833 additionalProperties .put (DOCUMENTATION_PROVIDER , "springdoc" );
38323834 additionalProperties .put (INTERFACE_ONLY , "true" );
38333835 additionalProperties .put (SKIP_DEFAULT_INTERFACE , "true" );
3834-
3836+
38353837 Map <String , File > files = generateFromContract ("src/test/resources/bugs/issue_13052.yaml" , additionalProperties );
38363838
38373839 // Custom Pageable model should be used instead of Spring's Pageable
@@ -3849,7 +3851,7 @@ public void springPaginatedWithNoDocumentationProvider() throws Exception {
38493851 additionalProperties .put (DOCUMENTATION_PROVIDER , "none" );
38503852 additionalProperties .put (INTERFACE_ONLY , "true" );
38513853 additionalProperties .put (SKIP_DEFAULT_INTERFACE , "true" );
3852-
3854+
38533855 Map <String , File > files = generateFromContract ("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml" , additionalProperties );
38543856
38553857 // Pageable should be added but no annotation imports
@@ -3912,7 +3914,7 @@ public void springPaginatedNoParamsNoContext() throws Exception {
39123914 additionalProperties .put (DOCUMENTATION_PROVIDER , "springdoc" );
39133915 additionalProperties .put (INTERFACE_ONLY , "true" );
39143916 additionalProperties .put (SKIP_DEFAULT_INTERFACE , "true" );
3915-
3917+
39163918 Map <String , File > files = generateFromContract ("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml" , additionalProperties );
39173919
39183920 // Test operation listAllPets which has no parameters except pageable
@@ -4018,15 +4020,15 @@ public void springPaginatedMixedOperations() throws Exception {
40184020 additionalProperties .put (DOCUMENTATION_PROVIDER , "springdoc" );
40194021 additionalProperties .put (INTERFACE_ONLY , "true" );
40204022 additionalProperties .put (SKIP_DEFAULT_INTERFACE , "true" );
4021-
4023+
40224024 Map <String , File > files = generateFromContract ("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml" , additionalProperties );
40234025
40244026 File petApi = files .get ("PetApi.kt" );
4025-
4027+
40264028 // Operation with x-spring-paginated should have Pageable
40274029 assertFileContains (petApi .toPath (), "fun findPetsByStatus(" );
40284030 assertFileContains (petApi .toPath (), "pageable: Pageable" );
4029-
4031+
40304032 // Operation without x-spring-paginated should NOT have Pageable
40314033 assertFileContains (petApi .toPath (), "fun addPet(" );
40324034 // Verify addPet doesn't have pageable (it has body param only)
@@ -4035,7 +4037,7 @@ public void springPaginatedMixedOperations() throws Exception {
40354037 content .indexOf ("fun addPet(" ),
40364038 content .indexOf (")" , content .indexOf ("fun addPet(" )) + 1
40374039 );
4038- Assert .assertFalse (addPetMethod .contains ("pageable" ),
4040+ Assert .assertFalse (addPetMethod .contains ("pageable" ),
40394041 "addPet should not have pageable parameter" );
40404042 }
40414043
@@ -4045,7 +4047,7 @@ public void springPaginatedWithServiceInterface() throws Exception {
40454047 additionalProperties .put (USE_TAGS , "true" );
40464048 additionalProperties .put (DOCUMENTATION_PROVIDER , "springdoc" );
40474049 additionalProperties .put (SERVICE_INTERFACE , "true" );
4048-
4050+
40494051 Map <String , File > files = generateFromContract ("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml" , additionalProperties );
40504052
40514053 // Test that pageable is in service interface
@@ -4064,7 +4066,7 @@ public void springPaginatedParameterOrdering() throws Exception {
40644066 additionalProperties .put (INTERFACE_ONLY , "true" );
40654067 additionalProperties .put (SKIP_DEFAULT_INTERFACE , "true" );
40664068 additionalProperties .put (INCLUDE_HTTP_REQUEST_CONTEXT , "true" );
4067-
4069+
40684070 Map <String , File > files = generateFromContract ("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml" , additionalProperties );
40694071
40704072 // Verify exact parameter ordering: allParams -> request -> pageable
@@ -4075,12 +4077,12 @@ public void springPaginatedParameterOrdering() throws Exception {
40754077 int methodStart = content .indexOf ("fun findPetsByStatus(" );
40764078 int methodEnd = content .indexOf ("): ResponseEntity" , methodStart );
40774079 String methodSignature = content .substring (methodStart , methodEnd );
4078-
4080+
40794081 // Verify order: status param comes before request, request comes before pageable
40804082 int statusPos = methodSignature .indexOf ("status:" );
40814083 int requestPos = methodSignature .indexOf ("request:" );
40824084 int pageablePos = methodSignature .indexOf ("pageable:" );
4083-
4085+
40844086 Assert .assertTrue (statusPos > 0 , "status parameter should exist" );
40854087 Assert .assertTrue (requestPos > statusPos , "request should come after status" );
40864088 Assert .assertTrue (pageablePos > requestPos , "pageable should come after request" );
@@ -4093,7 +4095,7 @@ public void springPaginatedDelegateCallPassesPageable() throws Exception {
40934095 additionalProperties .put (DOCUMENTATION_PROVIDER , "springdoc" );
40944096 additionalProperties .put (DELEGATE_PATTERN , "true" );
40954097 additionalProperties .put (INTERFACE_ONLY , "false" );
4096-
4098+
40974099 Map <String , File > files = generateFromContract ("src/test/resources/3_0/spring/petstore-with-spring-pageable.yaml" , additionalProperties );
40984100
40994101 // Verify that interface method calls delegate with pageable parameter
@@ -5009,6 +5011,47 @@ public void shouldDefaultToJackson3WhenSpringBoot4EnabledViaSetter() throws IOEx
50095011 assertFileNotContains (pomPath , "com.fasterxml.jackson.module" );
50105012 assertFileNotContains (pomPath , "jackson-datatype-jsr310" );
50115013 }
5012- }
50135014
5015+ @ Test
5016+ public void shouldAddParameterWithInHeaderWhenImplicitHeadersIsTrue () throws IOException {
5017+ File output = Files .createTempDirectory ("test" ).toFile ().getCanonicalFile ();
5018+ output .deleteOnExit ();
50145019
5020+ OpenAPI openAPI = new OpenAPIParser ()
5021+ .readLocation ("src/test/resources/bugs/issue_14418.yaml" , null , new ParseOptions ()).getOpenAPI ();
5022+
5023+ KotlinSpringServerCodegen codegen = new KotlinSpringServerCodegen ();
5024+ codegen .setLibrary (SPRING_BOOT );
5025+ codegen .setOutputDir (output .getAbsolutePath ());
5026+ codegen .additionalProperties ().put (KotlinSpringServerCodegen .INTERFACE_ONLY , "true" );
5027+ codegen .additionalProperties ().put (CodegenConstants .MODEL_PACKAGE , "xyz.model" );
5028+ codegen .additionalProperties ().put (CodegenConstants .API_PACKAGE , "xyz.controller" );
5029+ codegen .additionalProperties ().put (AbstractKotlinCodegen .IMPLICIT_HEADERS , "true" );
5030+
5031+ ClientOptInput input = new ClientOptInput ()
5032+ .openAPI (openAPI )
5033+ .config (codegen );
5034+
5035+ DefaultGenerator generator = new DefaultGenerator ();
5036+ generator .setGenerateMetadata (false );
5037+ Map <String , File > files = generator .opts (input ).generate ().stream ()
5038+ .collect (Collectors .toMap (File ::getName , Function .identity ()));
5039+
5040+ File testApi = files .get ("TestApi.kt" );
5041+ String content = Files .readString (testApi .toPath ());
5042+ String methodPattern = "fun test\\ s*\\ (.*?\\ )" ;
5043+ Pattern pattern = Pattern .compile (methodPattern );
5044+
5045+ Matcher matcher = pattern .matcher (content );
5046+ Assert .assertTrue (matcher .find (), "Method 'test' should be found in generated file" );
5047+
5048+ String methodSignature = matcher .group ();
5049+ Assert .assertFalse (methodSignature .contains ("testHeader" ),
5050+ "Header param 'testHeader' should NOT be in method signature when implicitHeaders=true" );
5051+
5052+ Assert .assertTrue (content .contains ("@Parameters" ),
5053+ "@Parameters annotation should be present" );
5054+ Assert .assertTrue (content .contains ("testHeader" ),
5055+ "Header name 'testHeader' should appear in the annotation" );
5056+ }
5057+ }
0 commit comments