null-point-exceptional
null-point-exceptional

Reputation: 647

Swagger/OpenApi Doesn't seem to understand my DTO field of type LocalTime, creating a JSON instead of a string for the request body

Issue with Swagger/OpenAPI v3 Not Respecting LocalTime Data Type in Spring Boot DTO

Environment:

Problem Description:

I'm working on a Spring Boot application where I have a DTO that includes a LocalTime field for entryTime. Despite using @JsonFormat to specify the time format, Swagger (via Springdoc OpenAPI) keeps displaying entryTime as a JSON object with hour, minute, second, and nano fields. This results in errors when I try to interact with the API through the swagger UI. Specifically I receive this error:

An error occurred: JSON parse error: Cannot deserialize value of type java.time.LocalTime from Object value (token JsonToken.START_OBJECT)

DTO property field in question:

    @NotNull(message = "Entry time is required")
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
    private LocalTime entryTime;

Expected API Request Body:

{
  "weight": 0,
  "ketoneLevel": 100,
  "entryDate": "2024-10-19",
  "entryTime": "00:00:00"
}

What Swagger/OpenAPI Shows:

Despite the annotations and configurations above, Swagger displays the entryTime field as follows:

{
  "weight": 0,
  "ketoneLevel": 100,
  "entryDate": "2024-10-19",
  "entryTime": {
    "hour": 0,
    "minute": 0,
    "second": 0,
    "nano": 0
  }
}

What I've Tried:

  1. Adding @JsonFormat Annotations:

    • I used @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss") on the LocalTime field, expecting Swagger to recognize it as a string.
  2. Using @Schema Annotation:

    • Tried adding @Schema(type = "string", pattern = "HH:mm:ss") to provide additional metadata for OpenAPI. This did not change the request body structure shown by Swagger.
  3. Adjusting Jackson Configuration:

    • Verified that Jackson is correctly serializing LocalTime as a string in responses, but this doesn't seem to influence how Swagger generates the request schema.
  4. Testing with Different Time Representations:

    • When sending a request with "entryTime": "2024-10-19T00:00:00.000", it successfully parses and stores the time in the database as expected:
      select * from fitness_entry;
      
      entry_id | entry_date | entry_time | ketone_level | weight | created_at           | member_id
      ---------+------------+------------+--------------+--------+----------------------+-----------
      1        | 2024-10-19 | 00:00:00   | 99.00        | 0.00   | 2024-10-19 00:00:00  | 1
      

Database Schema for fitness_entry:

\d fitness_entry;
                                              Table "public.fitness_entry"
    Column    |              Type              | Collation | Nullable |                     Default                     
--------------+--------------------------------+-----------+----------+-------------------------------------------------
 entry_id     | bigint                         |           | not null | nextval('fitness_entry_entry_id_seq'::regclass)
 entry_date   | date                           |           | not null | 
 entry_time   | time(6) without time zone      |           | not null | 
 ketone_level | numeric(4,2)                   |           |          | 
 weight       | numeric(5,2)                   |           | not null | 
 created_at   | timestamp(6) without time zone |           | not null | CURRENT_TIMESTAMP
 member_id    | bigint                         |           | not null | 

What does work:

Sending the request and manually overriding the entryTime as a string (e.g., "2024-10-19T00:00:00.000") does work, but I would like for the swagger documentation to reflect the truth.

Expected Outcome:

I want Swagger/OpenAPI to recognize the entryTime field as a simple string type in the request body, rather than an object with hour, minute, second, and nano fields.

Question:

How can I get Swagger/OpenAPI v3 to correctly interpret the LocalTime field as a string in the request body? Is there a specific annotation or configuration I’m missing to achieve this?

Any guidance or suggestions would be greatly appreciated! Cheers!

Upvotes: 0

Views: 468

Answers (1)

ketdev and
ketdev and

Reputation: 1

in application.properties

spring:
    jackson:
       serialization:
          write-dates-as-timestamps: false

Annotate entity field

@NotNull(message = "Entry time is required")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
@Schema(type = "string", pattern = "HH:mm:ss", example = "12:00:00")
private LocalTime entryTime;

use this spring configuration

@Configuration
public class SpringDocConfig {

    @Bean
    public OpenApiCustomiser customOpenApi() {
        return openApi -> openApi.getComponents()
                .addSchemas("LocalTime", new Schema<>().type("string").example("12:00:00"));
    }
}

Upvotes: 0

Related Questions