FasterXML / jackson-modules-java8

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

Deserialize Duration from int-like String (e.g. "3600") #232

Open jakub-bochenski opened 2 years ago

jakub-bochenski commented 2 years ago

I think even after #184 and related changes this is still not possible.

Trying to parse a string "3600" into a Duration field results in an exception: "Text cannot be parsed to a Duration"

I've tried adding @JsonFormat("SECONDS") but it seems this only applies to numeric input.

This behaviour is inconsistent with other parts of Jackson:

It would be nice if the handling for @JsonFormat also applied to int-like Strings, not only to actual Numbers

jakub-bochenski commented 2 years ago

PS. I came across this because there is a certain OAuth provider that does not conform to the rfc an sends the expires_in attribute as a string.

kupci commented 2 years ago

Thanks, though from a quick look at the code, looks like this should work. Therefore adding the 'test-needed', can be added to the "failing" package for now. Perhaps there's a config flag that needs to be set?

kupci commented 2 years ago

Ok, I think I see the issue now.. an int-like String isn't supported, since the code directly uses the Duration.parse method, and the parse method uses a special format:

Obtains a Duration from a text string such as PnDTnHnMn.nS. In other words, something like this:

"PT20.345S" -- parses as "20.345 seconds"

Therefore, there are actually checks in place to ensure the JsonFormat is ignored in this case.

So double minus points on the OAuth provider for not specifying the proper Duration format, per the specification:

"The formats accepted are based on the ISO-8601 duration format PnDTnHnMn.nS with days considered to be exactly 24 hours. "

Therefore, an argument could be made that the OAuth provider needs to fix their code, IMO.

All that said, I don't see why the JsonFormat could not be used, in the cases where there is (1) an int-like String (i.e. no characters, no P prefix) (2) a JsonFormat telling what the int-like String is, just as there is for an actual int. CC @cowtowncoder

cowtowncoder commented 2 years ago

Unfortunately @JsonFormat and shapes really refer to physical type of JSON value: JSON String that "looks like a number" is still a String, not number: there is no format for "stringified numbers". So there is no Shape to indicate such cases.

This does not mean that Durations could not be deserializers from such values but... I am not sure this is a good idea for general use. Perhaps this is one case where fully custom deserializers would make sense? Alternatively I guess simply having a new configuration option for DurationDeserializer would make sense, for indicating that "stringified numbers" are accepted same as JSON integers?

cowtowncoder commented 10 months ago

FWTW, newly (2.16) added JavaTimeFeature is a mechanism for adding simple on/off flags, one of which could allow enabling behavior suggested here. Something like:

JavaTimeFeature.ALLOW_STRINGIFIED_DURATION_VALUES

enabling of which would allow interpretation of "stringified" numbers as suggested.