jackson-datatype-jsr310, Instant, and formatting: 2 issues (2.6.2)

3,303 views
Skip to first unread message

da...@bakins-bits.com

unread,
Oct 22, 2015, 5:46:28 PM10/22/15
to jackson-user
I'm having a bit of trouble with Jackson-datatype-jsr310, java.time.Instant, and custom formatting.  This is with 2.6.2.
 
 
Basically, there are two issues: 
 
a) Using @JsonFormat with a pattern on a field of type Instant won't serialize the instance - gets an exception (see stack trace below, which goes with the gist).  I think it might be related to a problem described here http://stackoverflow.com/a/27483371/751579 .
 
b) Using a DateFormat formatter which forces milliseconds to be displayed ("...HH:mm:ss.SSSXXX") configured on an ObjectMapper an Instant which just happens to happen at some whole second boundary (milliseconds = 000) doesn't show any milliseconds, even though the formatter itself does emit the three zeros.  Which leads me to think it isn't being used. (Or I've done something else wrong.)
 
Let me know if it's my problem - or Jackson's.  If the latter, I'll file two issues.  (Or just one?)
 
Thanks! -- David Bakin
 
 

2015-10-22 14:43:40,224 0 DEBUG [net.javacrumbs.jsonunit.difference.diff] (main:) JSON documents are different:

Different value found in node "a". Expected "2015-07-23T01:02:03.000Z", got "2015-07-23T01:02:03Z".

2015-10-22 14:43:40,226 2 DEBUG [net.javacrumbs.jsonunit.difference.values] (main:) Comparing expected:

{"a":"2015-07-23T01:02:03.000Z"}

------------

with actual:

{"a":"2015-07-23T01:02:03Z"}

2015-10-22 14:43:40,226 2 DEBUG [net.javacrumbs.jsonunit.difference.diff] (main:) JSON documents are different:

Different value found in node "a". Expected "2015-07-23T01:02:03.000Z", got "2015-07-23T01:02:03Z".

2015-10-22 14:43:40,226 2 DEBUG [net.javacrumbs.jsonunit.difference.values] (main:) Comparing expected:

{"a":"2015-07-23T01:02:03.000Z"}

------------

with actual:

{"a":"2015-07-23T01:02:03Z"}

FAILED: serialize_an_instant_via_JsonFormat_annotation

java.lang.AssertionError: failed to serialize

at com.ispot.TestDateFormat.serialize_an_instant_via_JsonFormat_annotation(TestDateFormat.java:53)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:497)

at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)

at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)

at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:816)

at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1124)

at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)

at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)

at org.testng.TestRunner.privateRun(TestRunner.java:774)

at org.testng.TestRunner.run(TestRunner.java:624)

at org.testng.SuiteRunner.runTest(SuiteRunner.java:359)

at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354)

at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312)

at org.testng.SuiteRunner.run(SuiteRunner.java:261)

at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)

at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)

at org.testng.TestNG.runSuitesSequentially(TestNG.java:1191)

at org.testng.TestNG.runSuitesLocally(TestNG.java:1116)

at org.testng.TestNG.run(TestNG.java:1024)

at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:112)

at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:205)

at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:176)

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unsupported field: YearOfEra (through reference chain: com.ispot.HasInstantWithFormat["a"])

at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:210)

at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:177)

at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:199)

at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:683)

at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:157)

at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:130)

at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3554)

at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:2925)

at com.ispot.TestDateFormat.serialize_an_instant_via_JsonFormat_annotation(TestDateFormat.java:50)

... 24 more

Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra

at java.time.Instant.getLong(Instant.java:603)

at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)

at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2540)

at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)

at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746)

at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720)

at com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializerBase.serialize(InstantSerializerBase.java:87)

at com.fasterxml.jackson.datatype.jsr310.ser.InstantSerializerBase.serialize(InstantSerializerBase.java:33)

at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:693)

at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:675)

... 29 more

FAILED: serialize_an_instant_via_configured_mapper

java.lang.AssertionError: JSON documents are different:

Different value found in node "a". Expected "2015-07-23T01:02:03.000Z", got "2015-07-23T01:02:03Z".

at net.javacrumbs.jsonunit.fluent.JsonFluentAssert.failWithMessage(JsonFluentAssert.java:185)

at net.javacrumbs.jsonunit.fluent.JsonFluentAssert.isEqualTo(JsonFluentAssert.java:114)

at com.ispot.TestDateFormat.serialize_an_instant_via_configured_mapper(TestDateFormat.java:116)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

at java.lang.reflect.Method.invoke(Method.java:497)

at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)

at org.testng.internal.Invoker.invokeMethod(Invoker.java:639)

at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:816)

at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1124)

at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)

at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:108)

at org.testng.TestRunner.privateRun(TestRunner.java:774)

at org.testng.TestRunner.run(TestRunner.java:624)

at org.testng.SuiteRunner.runTest(SuiteRunner.java:359)

at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:354)

at org.testng.SuiteRunner.privateRun(SuiteRunner.java:312)

at org.testng.SuiteRunner.run(SuiteRunner.java:261)

at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)

at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)

at org.testng.TestNG.runSuitesSequentially(TestNG.java:1191)

at org.testng.TestNG.runSuitesLocally(TestNG.java:1116)

at org.testng.TestNG.run(TestNG.java:1024)

at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:112)

at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:205)

at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:176)

 

===============================================

Default test

Tests run: 2, Failures: 2, Skips: 0

===============================================

Tatu Saloranta

unread,
Oct 23, 2015, 1:00:50 PM10/23/15
to jackso...@googlegroups.com
On Thu, Oct 22, 2015 at 2:46 PM, <da...@bakins-bits.com> wrote:
I'm having a bit of trouble with Jackson-datatype-jsr310, java.time.Instant, and custom formatting.  This is with 2.6.2.
 
 
Basically, there are two issues: 
 
a) Using @JsonFormat with a pattern on a field of type Instant won't serialize the instance - gets an exception (see stack trace below, which goes with the gist).  I think it might be related to a problem described here http://stackoverflow.com/a/27483371/751579 .

This one seems to be from:


Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
 
so it sounds like something that the new Java8 Date/Time API itself has trouble with? I guess it could also be about usage, perhaps different calls are needed.
My expertise with this is unfortunately limited, so I don't really know whose fault it is.

 
b) Using a DateFormat formatter which forces milliseconds to be displayed ("...HH:mm:ss.SSSXXX") configured on an ObjectMapper an Instant which just happens to happen at some whole second boundary (milliseconds = 000) doesn't show any milliseconds, even though the formatter itself does emit the three zeros.  Which leads me to think it isn't being used. (Or I've done something else wrong.)
Would it be possible to try a stand-alone test with Java8 date/time, without invoking Jackson, and seeing if it might try to be clever and prune those trailing zeroes?
Or if anyone knows of a configuration option that may be relevant here (perhaps DateTimeFormat has on/off switch for such minimizations?).
 
 
Let me know if it's my problem - or Jackson's.  If the latter, I'll file two issues.  (Or just one?)


I wish I knew which one it is. But we do have others who are more knowledgeable, on the list, who I hope can suggest solutions.

-+ Tatu +-
 

--
You received this message because you are subscribed to the Google Groups "jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jackson-user...@googlegroups.com.
To post to this group, send email to jackso...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

da...@bakins-bits.com

unread,
Oct 23, 2015, 2:01:00 PM10/23/15
to jackson-user
Thanks for looking at this.  To the first point, the exception, the stack overflow link to here describes the problem and fix (I verified this works for me in very similar code not using Jackson) - you've got to tell the DateTimeFormatter the timezone explicitly with a withZone() call.  To the second point, line 115 in the gist shows that Java 8 by itself does not truncate those zeros.

-- David

Tom Mack

unread,
Oct 26, 2015, 2:50:25 PM10/26/15
to jackson-user
It is the default Instant formatter (the one that Instant.toString() uses)that trims the zeros.


The serializer for java.time.Instant could convert to a OffsetDateTime in UTC first if a pattern needs to be used.

Instant.now().atOffset(ZoneOffset.UTC).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))

da...@bakins-bits.com

unread,
Oct 26, 2015, 5:05:12 PM10/26/15
to jackson-user
I think your link to source code got garbled ...

But if I understand you, then the call to ObjectMapper.setDateFormat() with a SimpleDateFormat that has the required format followed by a call to ObjectMapper.setTimeZone() isn't used for Instant instances?

Seems like that's a bug I can create an issue for, eh?

Thanks! -- David

da...@bakins-bits.com

unread,
Oct 26, 2015, 5:06:13 PM10/26/15
to jackson-user
Yikes, forgot a link of my own, I'm talking about lines 81-85 here
Reply all
Reply to author
Forward
0 new messages