micronaut-projects / micronaut-projects/micronaut-openapi
JavaMicronautServerCodegen does not enforce required nullable request-body fields
- Dominant language
- Java
- Stars
- 114
- Forks
- 121
- Avg merge
- 2d 17h
- Merged PRs (30d)
- 25
Description
### Expected Behavior
For an OpenAPI request-body schema field that is both `required` and `nullable`, the generated Micronaut server endpoint should preserve or enforce the OpenAPI presence semantics:
- `{ "field": null }` is valid because the field is present and nullable.
- `{}` is invalid because the required field is absent.
This matters for full-replacement APIs where explicit `null` means "clear/reset this setting", while omission means the request is incomplete.
### Actual Behavior
With `JavaMicronautServerCodegen`, the generated request DTO uses a nullable Java property:
```java
@Nullable(inherited = true)
@JsonProperty(JSON_PROPERTY_FILE_SIZE_LIMIT)
private Long fileSizeLimit;
```
After request binding, both of these payloads produce `getFileSizeLimit() == null`:
```json
{ "fileSizeLimit": null }
```
```json
{}
```
At that point application code cannot tell whether the JSON property was explicitly present with `null` or omitted entirely. As a result, a server cannot implement the OpenAPI contract for `required + nullable` request fields without a pre-binding raw-body validator/filter.
### Steps To Reproduce
Use an OpenAPI schema like this for a server request body:
```yaml
UpdateThingDetails:
type: object
description: Full-replacement request payload.
required:
- enabled
- limit
- allowedValues
properties:
enabled:
type: boolean
limit:
type: integer
format: int64
nullable: true
minimum: 1
allowedValues:
type: array
nullable: true
minItems: 1
items:
type: string
```
Generate Micronaut server models with `JavaMicronautServerCodegen`.
Send a request body that omits `limit`:
```json
{
"enabled": true,
"allowedValues": null
}
```
The generated DTO sees `limit == null`, the same as if the client had sent:
```json
{
"enabled": true,
"limit": null,
"allowedValues": null
}
```
### Environment Information
- Micronaut OpenAPI Gradle plugin: `5.0.0`
- Generated class marker: `@Generated("io.micronaut.openapi.generator.JavaMicronautServerCodegen")`
- Server-side generated DTOs with Micronaut serde annotations
### Possible Solutions
Any of these would make the generated server contract enforceable:
- Validate request-body required field presence before DTO binding for generated server endpoints.
- Generate presence-aware DTO fields for nullable required properties.
- Generate a documented wrapper type for nullable required properties, similar to `JsonNullable`-style semantics.
- Document the expected Micronaut server pattern for enforcing OpenAPI `required + nullable` request fields if this is intentionally left to application code.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reproducing the issue with the UpdateThingDetails schema and generated JavaMicronautServerCodegen DTO, comparing an omitted nullable field with an explicit null. Determine whether the generated server contract can preserve required-field presence semantics; done means enforcing or clearly documenting the distinction for required nullable request fields.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, openapi
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 38/100