Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ private Object resolveModelToExample(String name, String mediaType, Schema schem
}

processedModels.add(name);
Map<String, Object> values = new HashMap<>();
Map<String, Object> values = new LinkedHashMap<>();
LOGGER.debug("Resolving model '{}' to example", name);
if (schema.getExample() != null) {
LOGGER.debug("Using example from spec: {}", schema.getExample());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
{{^lombok.Data}}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Fluent setter parameters now use the wrapped nullable/optional type, but the body wraps the argument again, causing invalid nested JsonNullable/Optional assignments.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache, line 147:

<comment>Fluent setter parameters now use the wrapped nullable/optional type, but the body wraps the argument again, causing invalid nested `JsonNullable`/`Optional` assignments.</comment>

<file context>
@@ -144,7 +144,7 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}
 
   {{! begin feature: fluent setter methods }}
-  public {{classname}} {{name}}({{>nullableAnnotation}}{{{datatypeWithEnum}}} {{name}}) {
+  public {{classname}} {{name}}({{>nullableAnnotation}}{{>nullableDataType}} {{name}}) {
     {{#openApiNullable}}
     this.{{name}} = {{#isNullable}}JsonNullable.of({{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}Optional.of{{#optionalAcceptNullable}}Nullable{{/optionalAcceptNullable}}({{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}}{{name}}{{#isNullable}}){{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}){{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}};
</file context>


{{! begin feature: fluent setter methods }}
public {{classname}} {{name}}({{>nullableAnnotation}}{{{datatypeWithEnum}}} {{name}}) {
public {{classname}} {{name}}({{>nullableAnnotation}}{{>nullableDataType}} {{name}}) {
{{#openApiNullable}}
this.{{name}} = {{#isNullable}}JsonNullable.of({{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}Optional.of{{#optionalAcceptNullable}}Nullable{{/optionalAcceptNullable}}({{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}}{{name}}{{#isNullable}}){{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}){{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}};
{{/openApiNullable}}
Expand Down Expand Up @@ -260,7 +260,7 @@ public {{>sealed}}class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}

{{^lombok.Setter}}
{{! begin feature: fluent setter methods for inherited properties }}
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
public {{classname}} {{name}}({{>nullableAnnotation}}{{>nullableDataType}} {{name}}) {
super.{{name}}({{name}});
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}
{{^lombok.Data}}

{{! begin feature: fluent setter methods }}
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
public {{classname}} {{name}}({{>nullableDataType}} {{name}}) {
{{#openApiNullable}}
this.{{name}} = {{#isNullable}}JsonNullable.of({{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}Optional.of({{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}}{{name}}{{#isNullable}}){{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}){{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}};
Comment on lines +158 to 160
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1: Fluent setters now accept nullable input but still call Optional.of(...), so passing null can throw NullPointerException for optional properties.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At modules/openapi-generator/src/main/resources/java-camel-server/pojo.mustache, line 158:

<comment>Fluent setters now accept nullable input but still call `Optional.of(...)`, so passing null can throw `NullPointerException` for optional properties.</comment>

<file context>
@@ -155,7 +155,7 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}
 
   {{! begin feature: fluent setter methods }}
-  public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
+  public {{classname}} {{name}}({{>nullableDataType}} {{name}}) {
     {{#openApiNullable}}
     this.{{name}} = {{#isNullable}}JsonNullable.of({{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}Optional.of({{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}}{{name}}{{#isNullable}}){{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}){{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}};
</file context>
Suggested change
public {{classname}} {{name}}({{>nullableDataType}} {{name}}) {
{{#openApiNullable}}
this.{{name}} = {{#isNullable}}JsonNullable.of({{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}Optional.of({{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}}{{name}}{{#isNullable}}){{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}){{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}};
public {{classname}} {{name}}({{>nullableDataType}} {{name}}) {
{{#openApiNullable}}
this.{{name}} = {{#isNullable}}JsonNullable.of({{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}Optional.ofNullable({{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}}{{name}}{{#isNullable}}){{/isNullable}}{{#useOptional}}{{^required}}{{^isNullable}}{{^isContainer}}){{/isContainer}}{{/isNullable}}{{/required}}{{/useOptional}};
{{/openApiNullable}}

{{/openApiNullable}}
Expand Down Expand Up @@ -280,7 +280,7 @@ public class {{classname}}{{#parent}} extends {{{parent}}}{{/parent}}{{^parent}}

{{^lombok.Setter}}
{{! begin feature: fluent setter methods for inherited properties }}
public {{classname}} {{name}}({{{datatypeWithEnum}}} {{name}}) {
public {{classname}} {{name}}({{>nullableDataType}} {{name}}) {
super.{{name}}({{name}});
return this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.openapitools.codegen;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.IntegerSchema;
import org.openapitools.codegen.examples.ExampleGenerator;
import org.testng.annotations.Test;

Expand All @@ -11,6 +13,7 @@

import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertNull;
import static org.testng.AssertJUnit.assertTrue;

public class ExampleGeneratorTest {
@Test
Expand Down Expand Up @@ -334,4 +337,77 @@ public void generateFromResponseSchemaWithAnyOfComposedModel() {
assertEquals(String.format(Locale.ROOT, "{%n \"example_schema_property\" : \"example schema property value\"%n}"), examples.get(0).get("example"));
assertEquals("200", examples.get(0).get("statusCode"));
}

@Test
public void testExamplePropertyOrderPreservation() {
OpenAPI openAPI = new OpenAPI();

// Create a schema with properties in a specific order
Schema<?> testSchema = new Schema<>();
testSchema.setType("object");

// Use LinkedHashMap to preserve property order as defined in spec
Map<String, Schema> properties = new LinkedHashMap<>();

// Add properties in the specific order: zebra, apple, mango, cherry, banana
IntegerSchema zebraSchema = new IntegerSchema();
zebraSchema.setExample(1);
properties.put("zebra", zebraSchema);

IntegerSchema appleSchema = new IntegerSchema();
appleSchema.setExample(2);
properties.put("apple", appleSchema);

IntegerSchema mangoSchema = new IntegerSchema();
mangoSchema.setExample(3);
properties.put("mango", mangoSchema);

IntegerSchema cherrySchema = new IntegerSchema();
cherrySchema.setExample(4);
properties.put("cherry", cherrySchema);

IntegerSchema bananaSchema = new IntegerSchema();
bananaSchema.setExample(5);
properties.put("banana", bananaSchema);

testSchema.setProperties(properties);

// Create examples map
Map<String, Schema> examples = new HashMap<>();
examples.put("TestModel", testSchema);

// Generate the example using the model name approach
ExampleGenerator generator = new ExampleGenerator(examples, openAPI);
Set<String> mediaTypeKeys = new TreeSet<>();
mediaTypeKeys.add("application/json");

List<Map<String, String>> generatedExamples = generator.generate(null, new ArrayList<>(mediaTypeKeys), "TestModel");

assertEquals(1, generatedExamples.size());
String exampleOutput = generatedExamples.get(0).get("example");

//System.out.println("Generated example output: " + exampleOutput);

// Verify the example contains properties in the correct order
// The order should be: zebra, apple, mango, cherry, banana
assertTrue(exampleOutput.contains("\"zebra\" : 1"));
assertTrue(exampleOutput.contains("\"apple\" : 2"));
assertTrue(exampleOutput.contains("\"mango\" : 3"));
assertTrue(exampleOutput.contains("\"cherry\" : 4"));
assertTrue(exampleOutput.contains("\"banana\" : 5"));

// Verify the order by checking the position of each field in the string
int zebraPos = exampleOutput.indexOf("\"zebra\"");
int applePos = exampleOutput.indexOf("\"apple\"");
int mangoPos = exampleOutput.indexOf("\"mango\"");
int cherryPos = exampleOutput.indexOf("\"cherry\"");
int bananaPos = exampleOutput.indexOf("\"banana\"");

//System.out.println("Field positions: zebra=" + zebraPos + ", apple=" + applePos + ", mango=" + mangoPos + ", cherry=" + cherryPos + ", banana=" + bananaPos);

assertTrue("zebra should come before apple", zebraPos < applePos);
assertTrue("apple should come before mango", applePos < mangoPos);
assertTrue("mango should come before cherry", mangoPos < cherryPos);
assertTrue("cherry should come before banana", cherryPos < bananaPos);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@ components:
schemas:
Category:
example:
name: Dogs
id: 1
name: Dogs
properties:
id:
example: 1
Expand All @@ -713,8 +713,8 @@ components:
name: category
Tag:
example:
name: name
id: 0
name: name
properties:
id:
format: int64
Expand All @@ -726,19 +726,19 @@ components:
name: tag
Pet:
example:
photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 10
name: doggie
category:
name: Dogs
id: 1
name: Dogs
photoUrls:
- photoUrls
- photoUrls
tags:
- name: name
id: 0
- name: name
id: 0
- id: 0
name: name
- id: 0
name: name
status: available
properties:
id:
Expand Down
22 changes: 11 additions & 11 deletions samples/client/echo_api/go/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@ components:
schemas:
Category:
example:
name: Dogs
id: 1
name: Dogs
properties:
id:
example: 1
Expand All @@ -713,8 +713,8 @@ components:
name: category
Tag:
example:
name: name
id: 0
name: name
properties:
id:
format: int64
Expand All @@ -726,19 +726,19 @@ components:
name: tag
Pet:
example:
photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 10
name: doggie
category:
name: Dogs
id: 1
name: Dogs
photoUrls:
- photoUrls
- photoUrls
tags:
- name: name
id: 0
- name: name
id: 0
- id: 0
name: name
- id: 0
name: name
status: available
properties:
id:
Expand Down
22 changes: 11 additions & 11 deletions samples/client/echo_api/java/apache-httpclient/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,8 @@ components:
schemas:
Category:
example:
name: Dogs
id: 1
name: Dogs
properties:
id:
example: 1
Expand All @@ -781,8 +781,8 @@ components:
name: category
Tag:
example:
name: name
id: 0
name: name
properties:
id:
format: int64
Expand All @@ -794,19 +794,19 @@ components:
name: tag
Pet:
example:
photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 10
name: doggie
category:
name: Dogs
id: 1
name: Dogs
photoUrls:
- photoUrls
- photoUrls
tags:
- name: name
id: 0
- name: name
id: 0
- id: 0
name: name
- id: 0
name: name
status: available
properties:
id:
Expand Down
22 changes: 11 additions & 11 deletions samples/client/echo_api/java/feign-gson/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,8 @@ components:
schemas:
Category:
example:
name: Dogs
id: 1
name: Dogs
properties:
id:
example: 1
Expand All @@ -781,8 +781,8 @@ components:
name: category
Tag:
example:
name: name
id: 0
name: name
properties:
id:
format: int64
Expand All @@ -794,19 +794,19 @@ components:
name: tag
Pet:
example:
photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 10
name: doggie
category:
name: Dogs
id: 1
name: Dogs
photoUrls:
- photoUrls
- photoUrls
tags:
- name: name
id: 0
- name: name
id: 0
- id: 0
name: name
- id: 0
name: name
status: available
properties:
id:
Expand Down
22 changes: 11 additions & 11 deletions samples/client/echo_api/java/native/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,8 @@ components:
schemas:
Category:
example:
name: Dogs
id: 1
name: Dogs
properties:
id:
example: 1
Expand All @@ -781,8 +781,8 @@ components:
name: category
Tag:
example:
name: name
id: 0
name: name
properties:
id:
format: int64
Expand All @@ -794,19 +794,19 @@ components:
name: tag
Pet:
example:
photoUrls:
- photoUrls
- photoUrls
name: doggie
id: 10
name: doggie
category:
name: Dogs
id: 1
name: Dogs
photoUrls:
- photoUrls
- photoUrls
tags:
- name: name
id: 0
- name: name
id: 0
- id: 0
name: name
- id: 0
name: name
status: available
properties:
id:
Expand Down
Loading