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

Jakarta annotations NotEmpty and NotBlank are not handled correctly for properties

Open dbarvitsky opened this issue 1 month ago • 0 comments

First off, thank you very much for your continued effort in maintaining spring-doc!

The following minor defect popped up for us during the recent round of upgrades.

Consider the following Java type:

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;

@Valid
public record StringConstraintsJsr380(
    @NotEmpty
    String nonEmpty,
    @NotBlank
    String notBlank) {
}

and a controller that accepts it as a POST payload body:

@RestController
@RequestMapping("/v1/types")
@Validated
public class SomeController {
  @PostMapping("string/jsr380")
  void doStringConstraintsJsr380(@Valid @RequestBody StringConstraintsJsr380 payload) {
  }
...
}

Discovered schema for SpringConstraintsJsr380 is as follows:

{
...
  "components": {
    "schemas": {
      "StringConstraintsJsr380": {
        "type": "object",
        "properties": {
          "nonEmpty": {
            "type": "string"
          },
          "notBlank": {
            "type": "string"
          }
        },
        "required": [
          "nonEmpty",
          "notBlank"
        ]
      }
    }
  }
}

This schema permits values of nonEmpty = "" and nonBlank = " ", while Java validation does not permit these values.

Per Jakarta, validation API:

  • NotEmpty applied to CharacterSequence requires at least one character, hence the nonEmpty must have minLength: 1
  • NotBlank requires at least one non-whitespace character, which probably is best expressed with pattern: "[^\\s]+".

To Reproduce Steps to reproduce the behavior:

  • spring-boot version 3.5.7
  • springdoc-openapi-starter-common 2.8.14
  • actual JSON - see above
  • expected JSON:
{
...
  "components": {
    "schemas": {
      "StringConstraintsJsr380": {
        "type": "object",
        "properties": {
          "nonEmpty": {
            "type": "string",
            "minLength": 1
          },
          "notBlank": {
            "type": "string",
            "pattern": "[^\\s]+" // Better options?
          }
        },
        "required": [
          "nonEmpty",
          "notBlank"
        ]
      }
    }
  }
}

Thank you in advance for looking into this!

dbarvitsky avatar Nov 19 '25 23:11 dbarvitsky