Can not deserialize value of type java.util.Date

We just started getting the below exception using the Java SDK while retrieving campaigns using the OutboundApi. It looks like the dateModified property for this campaign doesn't include the milliseconds portion of the value which is different from other date/time values in the message. We haven't changed any code on our end and the same call was working earlier today. Obviously based on the timestamp, the campaign itself was likely updated which may have caused it to set this value to what it currently is getting stuck on.

com.mypurecloud.sdk.ApiException: com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.util.Date from String "2016-08-18T14:31:29Z": not a valid representation (error: Failed to parse Date value '2016-08-18T14:31:29Z': Unparseable date: "2016-08-18T14:31:29Z")
at [Source: {"pageSize":25,"pageNumber":1,"total":2,"entities":[{"id":"40ebd7d9-cb8b-4e62-948b-0eebe5be5c51","name":"English Appt Reminder Call Flow","dateCreated":"2016-08-01T12:44:58.797Z","dateModified":"2016-08-18T14:31:29Z","version":66,"contactList":{"id":"0069fb90-5837-41cc-ab27-f5e2e0d911d1","name":"English Appt Reminder Call Flow","selfUri":"/api/v2/outbound/contactlists/0069fb90-5837-41cc-ab27-f5e2e0d911d1"},"dialingMode":"agentless","edgeGroup":{"id":"adb0866e-1766-4ecd-8a68-14b26ec9ad2b","name":"PureCloud Voice - IAD","selfUri":"/api/v2/telephony/providers/edges/edgegroups/adb0866e-1766-4ecd-8a68-14b26ec9ad2b"},"campaignStatus":"complete","phoneColumns":[{"columnName":"PatientIVRPhoneNumber","type":"Home"}],"abandonRate":5.0,"dncLists":[],"callableTimeSet":{"id":"f984504b-cb78-4db0-a3c2-faed2d016902","name":"Eskenazi Indiana Residents","selfUri":"/api/v2/outbound/callabletimesets/f984504b-cb78-4db0-a3c2-faed2d016902"},"callAnalysisResponseSet":{"id":"ecaaabe6-5596-4a8e-92b5-61c9b88b332a","name":"English Appt Reminder Call Flow","selfUri":"/api/v2/outbound/callanalysisresponsesets/ecaaabe6-5596-4a8e-92b5-61c9b88b332a"},"callerName":"Eskenazi Health","callerAddress":"3172194722","outboundLineCount":1,"ruleSets":[{"id":"cef33191-a8be-4777-a6c3-fe37c0c70219","name":"English: Eskenazi Appointment Reminder","selfUri":"/api/v2/outbound/rulesets/cef33191-a8be-4777-a6c3-fe37c0c70219"}],"skipPreviewDisabled":false,"previewTimeOutSeconds":0,"singleNumberPreview":false,"noAnswerTimeout":45,"selfUri":"/api/v2/outbound/campaigns/40ebd7d9-cb8b-4e62-948b-0eebe5be5c51"},{"id":"f40221a2-627d-4c13-a878-89b3d2b5c770","name":"PureCloud Appt Reminder Call Flow - Mark Test","dateCreated":"2016-07-20T19:05:29.516Z","dateModified":"2016-07-29T19:36:42.932Z","version":84,"contactList":{"id":"dbc03696-3833-4fb9-a6c2-d832f1cb36ba","name":"hc1 internal test mark","selfUri":"/api/v2/outbound/contactlists/dbc03696-3833-4fb9-a6c2-d832f1cb36ba"},"dialingMode":"agentless","edgeGroup":{"id":"adb0866e-1766-4ecd-8a68-14b26ec9ad2b","name":"PureCloud Voice - IAD","selfUri":"/api/v2/telephony/providers/edges/edgegroups/adb0866e-1766-4ecd-8a68-14b26ec9ad2b"},"campaignStatus":"complete","phoneColumns":[{"columnName":"PatientIVRPhoneNumber","type":"Cell"}],"abandonRate":5.0,"dncLists":[],"callableTimeSet":{"id":"0d8528f4-5cce-4eea-abf1-b0567843244f","name":"Eskenazi Indiana Residents Testing","selfUri":"/api/v2/outbound/callabletimesets/0d8528f4-5cce-4eea-abf1-b0567843244f"},"callAnalysisResponseSet":{"id":"6f9c87b6-c9b6-4312-a656-17b2a0e8d900","name":"PureCloud Appt Reminder Call Flow - Internal Test","selfUri":"/api/v2/outbound/callanalysisresponsesets/6f9c87b6-c9b6-4312-a656-17b2a0e8d900"},"callerName":"hc1.com","callerAddress":"3172194722","outboundLineCount":1,"ruleSets":[{"id":"1be3f92a-8d28-405d-a856-24ced652a8e3","name":"PureCloud Appt Reminder Call Flow","selfUri":"/api/v2/outbound/rulesets/1be3f92a-8d28-405d-a856-24ced652a8e3"}],"skipPreviewDisabled":false,"previewTimeOutSeconds":0,"singleNumberPreview":false,"noAnswerTimeout":30,"selfUri":"/api/v2/outbound/campaigns/f40221a2-627d-4c13-a878-89b3d2b5c770"}],"selfUri":"/api/v2/outbound/campaigns?pageSize=25&pageNumber=1","firstUri":"/api/v2/outbound/campaigns?pageSize=25&pageNumber=1","lastUri":"/api/v2/outbound/campaigns?pageSize=25&pageNumber=1","pageCount":1}; line: 1, column: 195] (through reference chain: com.mypurecloud.sdk.model.CampaignEntityListing["entities"]->java.util.ArrayList[0]->com.mypurecloud.sdk.model.Campaign["dateModified"])
at com.mypurecloud.sdk.ApiClient.invokeAPIVerbose(ApiClient.java:635) ~[platform-client-0.23.1.70.jar:na]

Are you seeing this with all responses now, or intermittently? Are you using the OutboundApi.getCampaigns() method? I'll take a look at this. It seems odd that Java can't parse that using the default parser.

I am seeing this exception in OutboundApi.getCampaigns() as well as OutboundApi.getCampaignCampaignId(), however it only happens in getCampaignCampaignId for campaign "40ebd7d9-cb8b-4e62-948b-0eebe5be5c51", if I retrieve a different campaign, it works correctly. When I call getCampaigns using Postman, I can see the format of dateModified is different only for that campaign. The only thing different is its missing the milliseconds portion of that field, but only for that one campaign.

Is this not similar to the post below?

It's similar in that it's a deserialization error, but the cause is different.

Tim,
I was able to clear this error by manually starting that specific campaign through the UI. That caused it to set a new dateModified value which was in the proper format including milliseconds. After doing that, the SDK can successfully retrieve the campaign.

This does cause some concern though that at any time a campaign could end up back in this state and cause our process to fail until we manually intervene. I think the correct solution is to guarantee the API always returns the timestamp in the full format.

That's good to know. I wonder if you just happened to start the campaign and the timestamp actually was 000 fractional seconds, so it didn't include it in the string. The SDK should be tolerant either way as the value that was sent is a valid timestamp. I have an issue logged to make sure the SDK can parse this format.

Tim,
We encountered this exception again, this time while calling the UutboundApi.getContactlistsContactlistIdExport() method. Again, the exception showed that the timestamp value returned by the API did not include the milliseconds portion. The actual value returned by the API was "2016-09-09T14:11:08Z"

I created a fork of the purecloud_api_sdk_java project in GitHub and committed a change that will allow the ApiClient to successfully handle this. Here's a link to the actual commit:

https://github.com/mark-preston/purecloud_api_sdk_java/commit/8efd3b913f70b2542190baccd36b333832d0c3e9

Would you be willing to merge this change into your official branch so it will be part of the SDK going forward?

Thanks!
Mark

Thanks! Let me test this out and I'll merge it if I don't find any issues. I looks good upon visual inspection.

edit: actually, I realized those changes were made to the generated code. All of that gets blown away every time the SDK is generated from the latest swagger definition. I'll have to reject the PR, but I can definitely use that code in the templates.

Sorry about that, I should have looked closer at how the whole project is built. Any chance the changes could be made in the next day or so? Our project is scheduled for go-live on Friday and it would be great if we could get this fix in and do some testing before then.

Tim is out on paternity leave for a couple weeks but I can take a stab at it.

Thanks Kevin, I appreciate it!

@mpreston, want to take a look at https://github.com/MyPureCloud/purecloud_api_sdk_java/releases/tag/0.31.1.83 ?

I see the new ApiDateFormat class in that build, but the ApiClient class is not using it. To fix the original issue, the ApiClient.buildDefaultDateFormat() method should be changed to return an instance of the new ApiDateFormat class instead of a SimpleDateFormat instance.

public static DateFormat buildDefaultDateFormat() {
        // Use RFC3339 format for date and datetime.
        // See http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
        // Use UTC as the default time zone.
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        return dateFormat;
}

should be changed to:

public static DateFormat buildDefaultDateFormat() {
        return new ApiDateFormat();
}

We don't really need to set the timezone here since its being set in the constructor in ApiDateFormat, but it also doesn't hurt anything if it still sets it here.

I'm stuck getting this to build properly on our build machine, it works fine locally though. I created API-1940 for Time to look into it when he gets back so in the meantime you can use your fork and pull into your fork if there are any changes in the sdk that you need. Thats why we made these open source.

@mpreston This should be fixed in the latest version, 0.37.2.107, as soon as it syncs to maven central. ApiClient.java now uses ApiDateFormat. Let me know if you have any further issues with it.

Thanks Tim, I'll give it a try and let you know if I have any issues.