You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently JsonFormat.timezone overwrites the timezone used for both deserialization and serialization. I would like a way to allow Instants/DateTimes to be read in correctly as seen, but then allow timezone to be specified for serialization.
Posible solution:
Allow for a new JsonFormat.fallbackTimezone. This would not override ZonedDateTime timezone on serialization AND it would not overwrite the provided timezone on deserialization. But it would provide one if needed (eg: Instant serialization, or deserialization from a pattern with no TZ or optional TZ that is not provided). This is somewhat more involved as a pattern that has an optional timezone yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX] would require looking at the provided value to determine if we need to use the fallbackTimezone during deserialization.
My Current workaround just ignores the JsonFormat.timezone in the InstantDeserializer.
Here is an example showing the issue:
public class Foo {
public static void main(String[] args) {
try {
ObjectMapper om = new ObjectMapper();
JavaTimeModule jtm = new JavaTimeModule();
//jtm.addDeserializer(Instant.class, FixedDeserializer.INSTANT);
om.registerModule(new JavaTimeModule());
// TEST 1 - Read value in with JsonFormat.timezone set
Bar bar = om.readValue("{\"fiz\":\"2016-09-20T16:37:02-02:00\"}", Bar.class);
// The Instant is incorrect, it used the @JsonFormat.timezone to overwride what was provided
System.out.println(bar.fiz); // 2016-09-20T21:37:02Z
// Value writes correctly if fiz was set correctly
System.out.println(om.writeValueAsString(bar)); //{"fiz":"2016-09-20T16:37:02.000-05:00"}
// TEST 2 - Read value in with JsonFormat.timezone unset
BarNoTz barNoTz = om.readValue("{\"fiz\":\"2016-09-20T16:37:02-02:00\"}", BarNoTz.class);
// The Instant is correct :)
System.out.println(barNoTz.fiz); // 2016-09-20T18:37:02Z
// Value cannot write, because it does not know what timezone to write in. Throws UnsupportedField: YearOfEra
//System.out.println(om.writeValueAsString(barNoTz)); // THROWN UnsupportedTemporalTypeException
} catch (IOException e) {
e.printStackTrace();
}
}
public static class Bar {
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]XXX",
timezone = "America/Chicago"
)
private Instant fiz;
public Instant getFiz() {
return fiz;
}
public void setFiz(Instant fiz) {
this.fiz = fiz;
}
}
public static class BarNoTz {
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]XXX"
)
private Instant fiz;
public Instant getFiz() {
return fiz;
}
public void setFiz(Instant fiz) {
this.fiz = fiz;
}
}
}
My current workaround:
public class FixedDeserializer<T extends Temporal> extends InstantDeserializer<T> {
public static final InstantDeserializer<Instant> INSTANT = new FixedDeserializer<>(
Instant.class, DateTimeFormatter.ISO_INSTANT,
Instant::from,
a -> Instant.ofEpochMilli(a.value),
a -> Instant.ofEpochSecond(a.integer, a.fraction),
null,
true // yes, replace +0000 with Z
);
public FixedDeserializer(Class<T> supportedType, DateTimeFormatter formatter, Function<TemporalAccessor, T> parsedToValue,
Function<FromIntegerArguments, T> fromMilliseconds, Function<FromDecimalArguments, T> fromNanoseconds,
BiFunction<T, ZoneId, T> adjust, boolean replace0000AsZ) {
super(supportedType, formatter, parsedToValue, fromMilliseconds, fromNanoseconds, adjust, replace0000AsZ);
}
public FixedDeserializer(InstantDeserializer<T> base, DateTimeFormatter f) {
super(base, f);
}
public FixedDeserializer(InstantDeserializer<T> base, Boolean adjustToContextTimezoneOverride) {
super(base, adjustToContextTimezoneOverride);
}
@SuppressWarnings("unchecked")
@Override
public JsonDeserializer<T> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException
{
JsonFormat.Value format = findFormatOverrides(ctxt, property, handledType());
if (format != null) {
if (format.hasPattern()) {
final String pattern = format.getPattern();
final Locale locale = format.hasLocale() ? format.getLocale() : ctxt.getLocale();
DateTimeFormatter df;
if (locale == null) {
df = DateTimeFormatter.ofPattern(pattern);
} else {
df = DateTimeFormatter.ofPattern(pattern, locale);
}
//FIXED to not allow overrides as I always use patterns that has timezones.
// if (format.hasTimeZone()) {
// df = df.withZone(format.getTimeZone().toZoneId());
// }
return withDateFormat(df);
}
// any use for TimeZone?
}
return this;
}
}
The text was updated successfully, but these errors were encountered:
cowtowncoder
changed the title
Instant Deserializer is overwriting timezone
Allow @JsonFormat.timezone use for serialization but not use on deserialization
Apr 10, 2018
Currently JsonFormat.timezone overwrites the timezone used for both deserialization and serialization. I would like a way to allow Instants/DateTimes to be read in correctly as seen, but then allow timezone to be specified for serialization.
Posible solution:
Allow for a new JsonFormat.fallbackTimezone. This would not override ZonedDateTime timezone on serialization AND it would not overwrite the provided timezone on deserialization. But it would provide one if needed (eg: Instant serialization, or deserialization from a pattern with no TZ or optional TZ that is not provided). This is somewhat more involved as a pattern that has an optional timezone
yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX]
would require looking at the provided value to determine if we need to use the fallbackTimezone during deserialization.My Current workaround just ignores the JsonFormat.timezone in the InstantDeserializer.
Here is an example showing the issue:
My current workaround:
The text was updated successfully, but these errors were encountered: