Skip to content

[BUG] [JAVA] [SPRING] Missing JSpecify @Nullable on fluent setter parameter for optional properties #23681

@Quin-Proctor-GGL

Description

@Quin-Proctor-GGL

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

When useJspecify is enabled, the generator correctly adds @NullMarked at the package level and applies @Nullable to fields, getter return types, and regular setter parameters for optional properties. However, the fluent setter parameters do not get @Nullable applied, creating an inconsistent nullness contract.

For example, given an optional firstName property, the generated code is:

// Field - correct
private @Nullable String firstName;

// Getter - correct
public @Nullable String getFirstName() { ... }

// Setter - correct
public void setFirstName(@Nullable String firstName) { ... }

// Fluent setter - INCORRECT (missing @Nullable on parameter)
public UserBase firstName(String firstName) { ... }

Under @NullMarked, the fluent setter parameter is effectively @nonnull, which means static analysis tools (e.g. NullAway, IntelliJ inspections) will flag passing null to the fluent setter as an error — even though the underlying field is nullable and the property is optional in the OpenAPI spec.

openapi-generator version

v7.22.0

OpenAPI declaration file content or url
openapi: 3.1.1
info:
  title: Example API
  version: 0.0.1
paths: {}
components:
  schemas:
    UserBase:
      type: object
      description: A base object for user details.
      properties:
        firstName:
          description: The user's first name.
          type: string
          minLength: 1
          maxLength: 32
          example: John
        lastName:
          description: The user's last name.
          type: string
          minLength: 1
          maxLength: 32
          example: Doe
        email:
          type: string
          format: email
          maxLength: 128
          example: john.doe@example.com
Generation Details
<generatorName>spring</generatorName>
<configOptions>
    <!-- Packages -->
    <apiPackage>...</apiPackage>
    <modelPackage>...</modelPackage>
    <invokerPackage>...</invokerPackage>

    <useSpringBoot4>true</useSpringBoot4>
    <useJspecify>true</useJspecify>
    <interfaceOnly>true</interfaceOnly>
    <hateoas>true</hateoas>
    <dateLibrary>java8</dateLibrary>
    <returnResponseEntity>true</returnResponseEntity>
    <useTags>true</useTags>

    <skipDefaultInterface>true</skipDefaultInterface>
    <useBeanValidation>true</useBeanValidation>
    <hideGenerationTimestamp>true</hideGenerationTimestamp>
</configOptions>
Steps to reproduce
  1. Create an OpenAPI spec with optional properties (properties not listed in required)
  2. Generate with useJspecify: true using the spring generator
  3. Observe that the generated package-info.java contains @NullMarked
  4. Observe that fields are annotated @Nullable, getters return @Nullable, and regular setters accept @Nullable
  5. Observe that fluent setters (e.g. public UserBase firstName(String firstName)) do not have @Nullable on the parameter
  6. Static analysis tools now report an error when passing null to the fluent setter

Actual output:

public UserBase firstName(String firstName) {
    this.firstName = firstName;
    return this;
}

Expected output:

public UserBase firstName(@Nullable String firstName) {
    this.firstName = firstName;
    return this;
}
Related issues/PRs

[java] [Spring] useJspecify for java clients and spring generator #23256
I can see the same issue happening in the server Foo class: https://github.com/OpenAPITools/openapi-generator/pull/23256/changes#diff-bc8ecb319983dd05e330050f16efc8465757a345be5e825ee559b943dfc11ca7
But not in the client Foo class: https://github.com/OpenAPITools/openapi-generator/pull/23256/changes#diff-f27dea557f26c8d1143994612fc1c88f19b52f7373b8169925be312634107846

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions