FasterXML / jackson-modules-java8

Set of support modules for Java 8 datatypes (Optionals, date/time) and features (parameter names)
Apache License 2.0
398 stars 116 forks source link

OffsetTimeSerializer not writing seconds for time object like 15:30:00Z (where seconds is 00) #299

Open marceloverdijk opened 7 months ago

marceloverdijk commented 7 months ago

When having a OffsetTime field with e.g. 15:00:00Z and serializing this with Jackson it outputs: 15:00Z and thus the seconds are lost.

Note I have the time module registered via JavaTimeModule().

Although one could argue that the seconds are not needed this gives some problems when validating outputted data against JSON schema. when using the JSON schema format time then the seconds are expected, see https://json-schema.org/understanding-json-schema/reference/string#dates-and-times without the seconds the JSON schema validator fails with: The value must be a valid time. (note I'm using Justify for schema validation)

Looking at the source code, I see this is done on purpose https://github.com/FasterXML/jackson-modules-java8/blob/master/datetime/src/main/java/tools/jackson/datatype/jsr310/ser/OffsetTimeSerializer.java#L92-L111

    private final void _serializeAsArrayContents(OffsetTime value, JsonGenerator g,
            SerializerProvider provider)
        throws JacksonException
    {
        g.writeNumber(value.getHour());
        g.writeNumber(value.getMinute());
        final int secs = value.getSecond();
        final int nanos = value.getNano();
        if ((secs > 0) || (nanos > 0)) {
            g.writeNumber(secs);
            if (nanos > 0) {
                if(useNanoseconds(provider)) {
                    g.writeNumber(nanos);
                } else {
                    g.writeNumber(value.get(ChronoField.MILLI_OF_SECOND));
                }
            }
        }
        g.writeString(value.getOffset().toString());
    }

Is it possible to override this behaviour?

Currently I think my only option is create a custom Serializer?

If not possible to override this behaviour would it be at least possible to change this _serializeAsArrayContents method from private to protected so one could simply extend this class and override this method?

marceloverdijk commented 7 months ago

Hmm, JSR310FormattedSerializerBase (which the OffsetTimeSerializer extends) is also package protected. So just making that method protected would not help unfortunately.

cowtowncoder commented 7 months ago

I would not be against relaxing visibility rules where necessary, fwtw (PRs welcome). But sounds like that might not work.

Aside from that, yes, it seems like we could use more configurability. In many cases we could use one of properties of @JsonFormat (which allows use both via annotation itself, and with "ConfigOverrides" which allows specifying JsonFormat.Value for given type) -- but I don't think that'd have suitable option here.

Which would leave 2 further options:

  1. Adding direct configurability to OffsetTimeSerializer -- probably simple setter method (instead of passing in constructor). Not super elegant but would work
  2. Addition of new JavaTimeFeature option (this was added in Jackson 2.16). One challenge is that ideally these settings should be relevant for more than one Date/Time value type. If similar "always include seconds" (... and how about Nanos?) needs exist for other value types, I think this would be the way to go.

I can't guarantee having time to work on this, but I always try to find time to help others if you wanted to try a PR. Wrt versioning, new functionality should go in 2.17 branch, but I could allow "dark launch" for safe enough features for 2.16 (2.16.2) since 2.17.0 won't be released for months.