swagger-api / swagger-api/swagger-codegen

Java Client Does Not Format date-time As Per Swagger Spec

Open
#1,527 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Mustache
Stars
17.8k
Forks
6k
PR merge metrics
No merged PRs in 30d

Description

This bug completely breaks any service which strictly enforces RFC3339 formatting (please reference the SimpleDateFormat JavaDoc).

In ApiClient.mustache the constructor is the following:

// Use ISO 8601 format for date and datetime.
// See https://en.wikipedia.org/wiki/ISO_8601
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");

// Use UTC as the default time zone.
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

date-time is supposed to follow RFC3339, however this outputs 2015-11-06T06:49:57.483+0000 which is NOT RFC3339 compliant. It does not output what was likely the desired behavior: 2015-11-06T06:49:57.483Z.

The problem is that Z is a reserved constant to indicate the RFC 822 time zone. It is getting interpreted, so dateFormat.format(new Date()) always has +0000 at the end, not the literal string "Z". This could be solved by replacing Z with XXX (ISO-8601 time zone formatting as of Java 7) or by putting the Z in single quotes like the T is to indicate that the literal string "Z" should always be appended and not an interpreted time zone.

However this is made more complicated because ApiClient delegates date formatting to Jackson in the JSON class when serializing and deserializing data for POST requests. Jackson uses the same date pattern by default when WRITE_DATES_AS_TIMESTAMPS is disabled on the ObjectMapper, meaning it has the same problem where a POST request containing a date-time will always have +0000 instead of "Z". By default Jackson uses StdDateFormat which does fuzzy parsing of dates so the difference in time zone formatting does not break when deserializing.

You can manually set a DateFormat on the ObjectMapper, however that inherently disables the fuzzy parsing. Simply putting yyyy-MM-dd'T'HH:mm:ss.SSSXXX as the format will not work because in RFC3339 the fractional time (SSS) is optional, so if the response does not contain it then the formatter will throw an exception.

There is no good workaround for this bug because the ObjectMapper in the JSON class is private so there is no way to override this behavior for a specific API without modifying the generated model/client classes or swagger-codegen's mustache files.

I am not quite sure what the best solution is here. At the very least, the date formatter for ApiClient and Jackson should be the same, probably by an overridden constructor in JSON.mustache with a DateFormat/pattern parameter that ApiClient could specify.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with ApiClient.mustache and JSON.mustache, then inspect how the private Jackson ObjectMapper formats and parses date-time values. Reproduce serialization with and without fractional seconds and verify RFC3339 output and parsing; done means the generated client and Jackson use compatible formatting without losing fuzzy parsing.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
api, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.