0

I use openapi-generator-maven-plugin to generate API models in my spring-boot application

pom.xml:

    <...>
    <dependencies>
        <...>
        <dependency>
            <groupId>org.openapitools</groupId>
            <artifactId>jackson-databind-nullable</artifactId>
            <version>0.2.2</version>
        </dependency>
        <...>
    </dependencies>
    <...>
    <build>
        <plugins>
            <plugin>
                <groupId>org.openapitools</groupId>
                <artifactId>openapi-generator-maven-plugin</artifactId>
                <version>6.0.1</version>
                <executions>
                    <execution>
                        <id>CLIENT-EVENT</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <configuration>
                            <inputSpec>
                                ${project.basedir}/src/main/resources/swagger/client_event.json
                            </inputSpec>
                            <generatorName>spring</generatorName>
                            <generateApiDocumentation>false</generateApiDocumentation>
                            <generateApiTests>false</generateApiTests>
                            <generateApis>false</generateApis>
                            <generateSupportingFiles>false</generateSupportingFiles>
                            <generateModelDocumentation>false</generateModelDocumentation>
                            <generateModelTests>false</generateModelTests>
                            <generateModels>true</generateModels>
                            <generateAliasAsModel>false</generateAliasAsModel>
                            <modelPackage>ru.sb.compliance.lcm.dto.client.event</modelPackage>
                            <modelsToGenerate>CreateClientEventRequestData,CreateClientEventResponseData</modelsToGenerate>
                            <configOptions>
                                <delegatePattern>true</delegatePattern>
                                <dateLibrary>java8</dateLibrary>
                            </configOptions>
                            <library>spring-boot</library>
                            <typeMappings>
                                <typeMapping>OffsetDateTime=LocalDateTime</typeMapping>
                            </typeMappings>
                            <importMappings>
                                <importMapping>java.time.OffsetDateTime=java.time.LocalDateTime</importMapping>
                            </importMappings>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <...>

The generated LocalDate/LocalDateTime fields in the model look like that:

public class CreateClientEventRequestData {

  @JsonProperty("factDt")
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  private LocalDateTime factDt;

  <...>

  public CreateClientEventRequestData factDt(LocalDateTime factDt) {
    this.factDt = factDt;
    return this;
  }

  @Valid 
  @Schema(name = "factDt", description = "дата и время мероприятия", required = false)
  public LocalDateTime getFactDt() {
    return factDt;
  }

  public void setFactDt(LocalDateTime factDt) {
    this.factDt = factDt;
  }

  <...>
}

When I use this model in API, factDt is serialized like an array:

"data": {
    <...>,
    "factDt":[2022,11,11,20,18,34,71000000],
    <...>
}

What I want to get is

public class CreateClientEventRequestData {

  @JsonProperty("factDt")
  @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd.MM.yyyy HH:mm:ss")
  private LocalDateTime factDt;

  <...>
}

so that factDt is serialized like a string:

"data": {
    <...>,
    "factDt": "11.11.2022 20:18:34",
    <...>
}

There is no way to set the default serialization pattern in spring-boot if no @JsonFormat annotation is set

I tried several SO suggestions but neither of them worked, here is what I tried:

Setting date format doesn't work even with a minimal example like that:

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.setTimeZone(TimeZone.getDefault());
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.setDateFormat(new SimpleDateFormat("dd.MM.yyyy HH:mm:ss"));

        System.out.println(
                // prints LocalDateTime in default ISO format and not in "dd.MM.yyyy HH:mm:ss" format...
                objectMapper.writeValueAsString(LocalDateTime.now())
        );
    }

All that makes the idea of generating models from swagger instead of implementing them in your code pretty much deficient...

Your help is greatly appreciated

1 Answers1

2

Starting from the end, here's what your minimal LocalDateTime serialization example should look like:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.setTimeZone(TimeZone.getDefault());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

String dateFormat = "dd.MM.yyyy HH:mm:ss";
objectMapper.setDateFormat(new SimpleDateFormat(dateFormat));

SimpleModule module = new SimpleModule();
module.addSerializer(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateFormat)));
objectMapper.registerModule(module);

log.info("serialized local date time = {}", objectMapper.writeValueAsString(LocalDateTime.now()));

This produces the expected output:

2022-11-19 23:45:21.794  INFO 24320 --- [           main] c.e.s.SpringWebDemoApplication           : serialized local date time = "19.11.2022 23:45:05"

As to your main question, adding the following bean will do the job of the desired LocalDateTime formatting during serialization without any changes to the generated model classes:

private static final String dateTimeFormat = "yyyy-MM-dd HH:mm:ss";

@Bean
public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
    return builder -> {
        builder.simpleDateFormat(dateTimeFormat);
        builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
    };
}

Make sure there's no other configuration of the Spring autoconfigured ObjectMapper in your project that might override these settings.

dekkard
  • 6,121
  • 1
  • 16
  • 26
  • Thank you for your answer but I have already tried creating Jackson2ObjectMapperBuilderCustomizer and it doesn't work unfortunately :( – Eduard Grigoryev Nov 21 '22 at 12:40
  • In fact this does work exactly as it should and was tested before posting. Without further details or a minimal reproducible example from you I doubt it will be possible to resolve your issue. – dekkard Nov 21 '22 at 13:41