openapi-generator icon indicating copy to clipboard operation
openapi-generator copied to clipboard

[REQ][spring] Null-Safety annotations

Open frecco75 opened this issue 2 years ago • 8 comments

Is your feature request related to a problem? Please describe.

Manage null safety for object properties with Spring annotations (@NonNull, @Nullable). Example: https://www.baeldung.com/spring-null-safety-annotations

Describe the solution you'd like

I'd like to add a config option useSpringNullSafety for the spring generator (false by default), to add Spring Null-Safety annotations (either @NonNull or@Nullable, depending of the nullable attribute of the OAS model).

Example:

Pet:
  properties:
    name:
       type: string
       example: 'scooby-doo'
       nullable: false
    breed:
        type: string
        example: 'German mastiff'
        nullable: true

should generate a model:

import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

@Generated(value = "org.openapitools.codegen.languages.SpringCodegen")
public class Pet {

  @JsonProperty("name")
  @NonNull
  private String name;

  @JsonProperty("breed")
  @Nullable
  private String breed = null;

  public Pet name(@NonNull String name) {
    this.name = name;
    return this;
  }

  /**
   * Get name
   * @return name
  */
  
  @Schema(name = "name", example = "scooby-doo", required = false)
  @NonNull
  public String getName() {
    return name;
  }

  public void setName(@NonNull String name) {
    this.name = name;
  }

  public Pet breed(@Nullable String breed) {
    this.breed = breed;
    return this;
  }

  /**
   * Get breed
   * @return breed
  */
  
  @Schema(name = "breed", example = "German mastiff", required = false)
  @Nullable
  public String getBreed() {
    return breed;
  }

  public void setBreed(@Nullable String breed) {
    this.breed = breed;
  }

 ....
}

Describe alternatives you've considered

Maybe it should be similar to the useOptional config option, so that it should be based on the required OpenAPI attribute.

Additional context

It is better for Kotlin interoparibilty. As it is mentionned in Kotlin reference, Java object are natively resolved as platform type. With contextual annotations, the Kotlin compiler can provide null-safety type checking.

https://kotlinlang.org/docs/java-interop.html#null-safety-and-platform-types

frecco75 avatar Jan 11 '23 15:01 frecco75

That was done recently for the regular Java clients https://github.com/OpenAPITools/openapi-generator/issues/19600 but not for Spring unfortunately.

slobodator avatar Dec 05 '24 11:12 slobodator

If I am not mistaken, @Nullable should mark either non-required fields or ones with nullable: true

slobodator avatar Dec 05 '24 11:12 slobodator

It would be a very welcome change. And it makes a lot of sense to replicate it for the Spring generator if it is already done for Java clients.

In addition, it would be nice if the annotations are configurable (in order to support not only those from Spring, but also org.jspecify.annotations NonNull and Nullable, etc).

pcuriel avatar Dec 17 '24 17:12 pcuriel

@pcuriel I've just submitted the PR. Preferred to use @Nullable from Spring. That is not I am against JSpecify one but it should be done as a separate story. Also, I didn't use @NonNull as the generator creates an empty constructor and the default value is assigned to null. So, to keep it simply and compatible there are no configurations introduced.

slobodator avatar Dec 18 '24 11:12 slobodator

Thanks for the PR. You should also handle @NonNull (https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/lang/NonNull.html) for fields with nullable: false for good interpolation with Kotlin ;)

frecco75 avatar Dec 18 '24 13:12 frecco75

@frecco75 I was thinking about it but for the required and non-nullable (nullable: false with is a default) the generator creates

public class Pet {

  @JsonProperty("name")
  private String requiredName = null;

  public Pet() {
    super();
  }
  ...
}

I am not confident that it is a good idea to annotate that requiredName with @NonNull.

Also, my goal was to prevent dummy NPEs, not to make the good interpolation with Kotlin.

Don't get me wrong, I would be happy to put NonNull as well but it requires more changes.

slobodator avatar Dec 18 '24 13:12 slobodator

The Spring Framework is transitioning to JSpecify with all its projects. So, the Spring annotations will eventually be deprecated. What's the state of supporting JSpecify? I'm able to generate the field annotations using Mustache but not the setters.

simasch avatar Jun 16 '25 13:06 simasch

As @simasch mentioned, the Spring annotations will be deprecated. Any update on support for JSpecify?

CGradysRewe avatar Dec 10 '25 07:12 CGradysRewe