Description
When using the spring generator with useJspecify=true, generated API interfaces can contain @Nullable in parameter types/signatures without the required import:
import org.jspecify.annotations.Nullable;
This causes compilation failures in generated sources.
Confirmed affected case
Confirmed with:
- generator:
spring
- library:
spring-cloud
- options:
useJspecify=true
openApiNullable=false
useSpringBoot3=true
Generated output example
Generated Spring API interfaces can contain method parameters such as:
ResponseEntity<APIProxyDeploymentDetailsEnv> getAPIProxyDeploymentEnv(
@Parameter(name = "org_name", description = "Organization name.", required = true, in = ParameterIn.PATH)
@PathVariable("org_name")
@Nullable String orgName,
@Parameter(name = "env_name", description = "Environment name.", required = true, in = ParameterIn.PATH)
@PathVariable("env_name")
String envName,
@Parameter(name = "api_name", description = "API proxy name.", required = true, in = ParameterIn.PATH)
@PathVariable("api_name")
String apiName
);
but the generated imports do not include:
import org.jspecify.annotations.Nullable;
This causes compilation errors like:
error: cannot find symbol
symbol: class Nullable
Upstream source inspection
While investigating the generator source, this appears to be in the shared Spring parameter/import path rather than in any project-specific template customization.
Relevant files in this repository:
modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustache
modules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustache
modules/openapi-generator/src/main/resources/JavaSpring/headerParams.mustache
modules/openapi-generator/src/main/resources/JavaSpring/bodyParams.mustache
modules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustache
modules/openapi-generator/src/main/resources/JavaSpring/nullableAnnotation.mustache
modules/openapi-generator/src/main/resources/JavaSpring/optionalDataType.mustache
modules/openapi-generator/src/main/resources/JavaSpring/api.mustache
modules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-http-interface/api.mustache
modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.java
modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.java
In particular:
SpringCodegen sets the mapping:
importMapping.put("Nullable", useJspecify ? "org.jspecify.annotations.Nullable" : "org.springframework.lang.Nullable");
AbstractJavaCodegen.applyJspecify() also maps Nullable to org.jspecify.annotations.Nullable.
AbstractJavaCodegen.addNullableImportForOperation(...) adds the Nullable import only when a parameter matches notRequiredOrIsNullable().
AbstractJavaCodegen.JSpecifyNullableLambda / jSpecifyDatatype are involved in moving @Nullable into the type position.
That means there is at least one Spring generation path where @Nullable reaches the rendered signature but codegenOperation.imports does not receive Nullable.
Scope / likely affected variants
This is confirmed for spring + library=spring-cloud.
From source inspection, the same shared Spring parameter partials are reused by other Spring generator variants, so it is worth validating at least:
spring + library=spring-boot
spring + library=spring-http-interface
- delegate/interface generation paths using
JavaSpring/api.mustache
I am not claiming all of those are confirmed broken, only that they appear to share the same template path and should be checked.
Expected behavior
Whenever @Nullable is emitted and useJspecify=true, the generated file should also include:
import org.jspecify.annotations.Nullable;
Actual behavior
@Nullable appears in generated Spring API signatures, but the corresponding import is sometimes missing.
Workaround
As a workaround, I post-process generated files and inject the missing import whenever @Nullable is present but the import is missing:
// OAG spring-cloud template emits @Nullable on required object-type parameters but
// doesn't always add the import when useJspecify=true (known generator bug).
// Post-process to ensure the import is present wherever @Nullable is used.
fileTree(layout.buildDirectory.dir("generated-code")).matching {
include '**/*.java'
}.each { file ->
def text = file.text
if (text.contains('@Nullable')
&& !text.contains('import org.jspecify.annotations.Nullable;')) {
file.text = text.replaceFirst(
'(package [^;]+;\\s*\\n)',
'$1import org.jspecify.annotations.Nullable;\n'
)
}
}
Version
Observed with:
- OpenAPI Generator:
7.22.0
Suggested fix
Please review the Spring generator import registration for JSpecify-enabled parameter rendering and ensure that every code path that can emit @Nullable also registers Nullable in the operation/class imports.
Description
When using the
springgenerator withuseJspecify=true, generated API interfaces can contain@Nullablein parameter types/signatures without the required import:This causes compilation failures in generated sources.
Confirmed affected case
Confirmed with:
springspring-clouduseJspecify=trueopenApiNullable=falseuseSpringBoot3=trueGenerated output example
Generated Spring API interfaces can contain method parameters such as:
but the generated imports do not include:
This causes compilation errors like:
Upstream source inspection
While investigating the generator source, this appears to be in the shared Spring parameter/import path rather than in any project-specific template customization.
Relevant files in this repository:
modules/openapi-generator/src/main/resources/JavaSpring/pathParams.mustachemodules/openapi-generator/src/main/resources/JavaSpring/queryParams.mustachemodules/openapi-generator/src/main/resources/JavaSpring/headerParams.mustachemodules/openapi-generator/src/main/resources/JavaSpring/bodyParams.mustachemodules/openapi-generator/src/main/resources/JavaSpring/cookieParams.mustachemodules/openapi-generator/src/main/resources/JavaSpring/nullableAnnotation.mustachemodules/openapi-generator/src/main/resources/JavaSpring/optionalDataType.mustachemodules/openapi-generator/src/main/resources/JavaSpring/api.mustachemodules/openapi-generator/src/main/resources/JavaSpring/libraries/spring-http-interface/api.mustachemodules/openapi-generator/src/main/java/org/openapitools/codegen/languages/SpringCodegen.javamodules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractJavaCodegen.javaIn particular:
SpringCodegensets the mapping:AbstractJavaCodegen.applyJspecify()also mapsNullabletoorg.jspecify.annotations.Nullable.AbstractJavaCodegen.addNullableImportForOperation(...)adds theNullableimport only when a parameter matchesnotRequiredOrIsNullable().AbstractJavaCodegen.JSpecifyNullableLambda/jSpecifyDatatypeare involved in moving@Nullableinto the type position.That means there is at least one Spring generation path where
@Nullablereaches the rendered signature butcodegenOperation.importsdoes not receiveNullable.Scope / likely affected variants
This is confirmed for
spring+library=spring-cloud.From source inspection, the same shared Spring parameter partials are reused by other Spring generator variants, so it is worth validating at least:
spring+library=spring-bootspring+library=spring-http-interfaceJavaSpring/api.mustacheI am not claiming all of those are confirmed broken, only that they appear to share the same template path and should be checked.
Expected behavior
Whenever
@Nullableis emitted anduseJspecify=true, the generated file should also include:Actual behavior
@Nullableappears in generated Spring API signatures, but the corresponding import is sometimes missing.Workaround
As a workaround, I post-process generated files and inject the missing import whenever
@Nullableis present but the import is missing:Version
Observed with:
7.22.0Suggested fix
Please review the Spring generator import registration for JSpecify-enabled parameter rendering and ensure that every code path that can emit
@Nullablealso registersNullablein the operation/class imports.