Skip to content

[BUG][JAVA][restclient] useJackson3: createDefaultMapper(null) drops the default DateFormat, so date-time fields serialize as epoch numbers #24588

Description

@anatoly-tamarack

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

The useJackson3=false branch substitutes a default DateFormat when the argument is null. The
Jackson 3 branch passes null straight through:

{{^useJackson3}}
if (null == dateFormat) {
    dateFormat = createDefaultDateFormat();      // absent from the Jackson 3 branch
}
mapper.setDateFormat(dateFormat);

{{#useJackson3}}
return JsonMapper.builder()
    .defaultDateFormat(dateFormat)               // null passed straight through

The parameter is still @Nullable, and the generator's own entry points call it with a hardcoded
null — buildRestClientBuilder() and buildRestClient() both do createDefaultMapper(null). With
no DateFormat set, nothing clears WRITE_DATES_AS_TIMESTAMPS, so format: date-time properties
are written as epoch numbers instead of RFC 3339. A server binding such a property to
OffsetDateTime rejects the request.

Actual vs expected output

Same model, same value, only useJackson3 flipped:

useJackson3=false (expected) : {"clientId":"client-1","issuedAt":"2026-08-01T17:30:00Z"}
useJackson3=true  (actual)   : {"clientId":"client-1","issuedAt":1785605400.000000000}

Worth noting for diagnosis: a client built the documented way holds two differently configured
mappers. ApiClient(RestClient) builds a correct one for its own field, while the RestClient
passed in already baked the broken one into its converter — so the client looks correctly configured
while the wire bytes are not:

apiClient.getJsonMapper() writes : "2026-08-01T17:30:00Z"
the converter's mapper writes    : 1785605400.000000000
openapi-generator version

7.23.0, and still present in ApiClient.mustache on master (verified by reading the template, not by
building master). Regression relative to useJackson3=false; introduced with #23023.

OpenAPI declaration file content or url
openapi: 3.0.3
info: { title: repro, version: "1.0.0" }
paths:
  /clients:
    post:
      operationId: createClient
      requestBody:
        content:
          application/json:
            schema: { $ref: "#/components/schemas/RegisteredClient" }
      responses:
        "200": { description: ok }
components:
  schemas:
    RegisteredClient:
      type: object
      properties:
        clientId: { type: string }
        issuedAt: { type: string, format: date-time }
Generation Details
generatorName: java
library: restclient
additionalProperties:
  useSpringBoot4: "true"
  useJackson3: "true"

Spring Framework 7.0.8 / Spring Boot 4, Jackson 3.1.5, Java 25.

Steps to reproduce
  1. Generate the spec above with the config above.
  2. ApiClient client = new ApiClient(ApiClient.buildRestClientBuilder().build()).setBasePath(...);
  3. createClient(...) with issuedAt populated → the request body carries an epoch number.
  4. Regenerate with useJackson3=false → the same call sends "2026-08-01T17:30:00Z".
Related issues/PRs
Suggest a fix

Restore the fallback the Jackson 2 branch has:

public static JsonMapper createDefaultMapper(@Nullable DateFormat dateFormat) {
    return JsonMapper.builder()
        .defaultDateFormat(dateFormat != null ? dateFormat : createDefaultDateFormat())
        ...

Alternatively have buildRestClientBuilder() / buildRestClient() pass createDefaultDateFormat()
instead of null — though the @Nullable contract suggests the fallback belongs in the method.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions