Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -968,11 +968,6 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
if (model.getVendorExtensions().containsKey("x-jackson-optional-nullable-helpers")) {
model.imports.add("Arrays");
}

// to prevent inheritors (JavaCamelServerCodegen etc.) mistakenly use it
if (getName().contains("spring")) {
model.imports.add("Nullable");
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

cc @slobodator who made these changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@wing328 Let me share my opinion
Why the code was moved (not removed)
The problem (Issue #22788):
Array-type models like ResultCodes (type: array) were missing the Nullable import
The code was in postProcessModelProperty, which is called per property
Array-type models may have no properties or not trigger postProcessModelProperty the same way
Result: array-type models didn't get the Nullable import → compilation error
The solution:
Move the code from postProcessModelProperty to fromModel
fromModel is called once per model, regardless of properties
This ensures all models (including array-type) get the Nullable import
Why not keep it in both places?
It would add the import twice for regular models
fromModel is the right place because it handles all models uniformly
Current state:
The code is in fromModel (line 987-990)
It includes the enum check to skip enum models
Array-type models now get the import correctly
The code wasn't removed; it was moved to fix the array-type model bug.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thanks for sharing more

}

@Override
Expand All @@ -989,6 +984,8 @@ public CodegenModel fromModel(String name, Schema model) {
codegenModel.imports.remove("Schema");
}

addSpringNullableImport(codegenModel.imports);

return codegenModel;
}

Expand Down Expand Up @@ -1052,11 +1049,7 @@ public CodegenOperation fromOperation(String path, String httpMethod, Operation
codegenOperation.imports.addAll(provideArgsClassSet);
}

// to prevent inheritors (JavaCamelServerCodegen etc.) mistakenly use it
if (getName().contains("spring")) {
codegenOperation.allParams.stream().filter(CodegenParameter::notRequiredOrIsNullable).findAny()
.ifPresent(p -> codegenOperation.imports.add("Nullable"));
}
addSpringNullableImportForOperation(codegenOperation);

if (reactive) {
if (DocumentationProvider.SPRINGFOX.equals(getDocumentationProvider())) {
Expand Down Expand Up @@ -1219,4 +1212,23 @@ public List<VendorExtension> getSupportedVendorExtensions() {
extensions.add(VendorExtension.X_SPRING_API_VERSION);
return extensions;
}

private boolean isSpringCodegen() {
return getName().contains("spring");
}

private void addSpringNullableImport(Set<String> imports) {
if (isSpringCodegen()) {
imports.add("Nullable");
}
}

private void addSpringNullableImportForOperation(CodegenOperation codegenOperation) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

please add a docstring explaining what this function does

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added JavaDoc comment to addSpringNullableImportForOperation method

if (isSpringCodegen()) {
codegenOperation.allParams.stream()
.filter(CodegenParameter::notRequiredOrIsNullable)
.findAny()
.ifPresent(param -> codegenOperation.imports.add("Nullable"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6223,4 +6223,37 @@ public void testExtensionsOnSchema_issue9183() throws IOException {
));
}

@Test
public void shouldAddNullableImportForArrayTypeModels() throws IOException {
File output = Files.createTempDirectory("test").toFile().getCanonicalFile();
output.deleteOnExit();

final OpenAPI openAPI = TestUtils.parseFlattenSpec(
"src/test/resources/3_0/spring/petstore-with-fake-endpoints-models-for-testing-with-spring-pageable.yaml");
final SpringCodegen codegen = new SpringCodegen();
codegen.setOpenAPI(openAPI);
codegen.setOutputDir(output.getAbsolutePath());
codegen.additionalProperties().put(INTERFACE_ONLY, "true");
codegen.additionalProperties().put(CodegenConstants.GENERATE_ALIAS_AS_MODEL, "true");

ClientOptInput input = new ClientOptInput();
input.openAPI(openAPI);
input.config(codegen);

DefaultGenerator generator = new DefaultGenerator();
generator.setGenerateMetadata(false);
generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false");
generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false");

Map<String, File> files = generator.opts(input).generate().stream()
.collect(Collectors.toMap(File::getName, Function.identity()));

// AnimalFarm is an array-type model with no properties (issue #22788)
JavaFileAssert.assertThat(files.get("AnimalFarm.java"))
.hasImports("org.springframework.lang.Nullable");
JavaFileAssert.assertThat(files.get("Pet.java"))
.hasImports("org.springframework.lang.Nullable");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src/Api</directory>
<directory suffix=".php">./src/Model</directory>
<directory suffix=".php">./src\/Api</directory>
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
<directory suffix=".php">./src\/Model</directory>
</include>
</coverage>
<testsuites>
Expand Down
4 changes: 2 additions & 2 deletions samples/client/echo_api/php-nextgen/phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src/Api</directory>
<directory suffix=".php">./src/Model</directory>
<directory suffix=".php">./src\/Api</directory>
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
<directory suffix=".php">./src\/Model</directory>
</include>
</coverage>
<testsuites>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="./vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./src/Api</directory>
<directory suffix=".php">./src/Model</directory>
<directory suffix=".php">./src\/Api</directory>
<directory suffix=".php">./src\/Model</directory>
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
</include>
</coverage>
<testsuites>
Expand Down
2 changes: 1 addition & 1 deletion samples/client/petstore/powershell/docs/FormatTest.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ $FormatTest = Initialize-PSPetstoreFormatTest -Integer null `
-String null `
-Byte null `
-Binary null `
-Date Sun Feb 02 00:00:00 UTC 2020 `
-Date Sat Feb 01 16:00:00 PST 2020 `
-DateTime 2007-12-03T10:15:30+01:00 `
-Uuid 72f98069-206d-4f12-9f12-3d1e525a8e84 `
-Password null `
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class Pet {
private BigDecimal price = new BigDecimal("32000000000");

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private OffsetDateTime lastFeed = OffsetDateTime.parse("1973-12-19T11:39:57Z[UTC]", java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(java.time.ZoneId.systemDefault()));
private OffsetDateTime lastFeed = OffsetDateTime.parse("1973-12-19T03:39:57-08:00[America/Los_Angeles]", java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(java.time.ZoneId.systemDefault()));

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate dateOfBirth = LocalDate.parse("2021-01-01");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class Pet {
private BigDecimal price = new BigDecimal("32000000000");

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private OffsetDateTime lastFeed = OffsetDateTime.parse("1973-12-19T11:39:57Z[UTC]", java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(java.time.ZoneId.systemDefault()));
private OffsetDateTime lastFeed = OffsetDateTime.parse("1973-12-19T03:39:57-08:00[America/Los_Angeles]", java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME.withZone(java.time.ZoneId.systemDefault()));

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
private LocalDate dateOfBirth = LocalDate.parse("2021-01-01");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.net.URI;
import java.util.Objects;
import org.springframework.lang.Nullable;
import com.fasterxml.jackson.annotation.JsonValue;
import org.openapitools.jackson.nullable.JsonNullable;
import java.time.OffsetDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public virtual IActionResult FakeNullableExampleTest()
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
// return StatusCode(200, default);
string exampleJson = null;
exampleJson = "{\n \"nullableName\" : \"nullableName\",\n \"name\" : \"name\"\n}";
exampleJson = "{\r\n \"nullableName\" : \"nullableName\",\r\n \"name\" : \"name\"\r\n}";
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

did you use windows wsl to update the samples?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, samples were regenerated on Windows, which explains the CRLF line endings in the string literals.

Copy link
Copy Markdown
Contributor Author

@spider-yamet spider-yamet Feb 2, 2026

Choose a reason for hiding this comment

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

And I have already resolved these WIndows WSL related issues. @wing328


var example = exampleJson != null
? JsonConvert.DeserializeObject<TestNullable>(exampleJson)
Expand Down
Loading