Skip to content

Commit 660a33a

Browse files
author
Max Klyga
committed
Fix date deserialization by ignoring microseconds
1 parent 60b3ebd commit 660a33a

File tree

7 files changed

+59
-15
lines changed

7 files changed

+59
-15
lines changed

src/main/java/io/getstream/core/Stream.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.getstream.core;
22

33
import com.fasterxml.jackson.annotation.JsonFormat;
4+
import com.fasterxml.jackson.annotation.OptBoolean;
45
import com.fasterxml.jackson.core.JsonProcessingException;
56
import io.getstream.core.exceptions.StreamException;
67
import io.getstream.core.http.HTTPClient;
@@ -110,7 +111,7 @@ public CompletableFuture<Activity> updateActivityByForeignID(Token token, String
110111
String[] propertiesToUnset = unset;
111112
final byte[] payload = toJSON(new Object() {
112113
public final String foreign_id = foreignID;
113-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
114+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", lenient = OptBoolean.FALSE, timezone = "UTC")
114115
public final Date time = timestamp;
115116
public final Map<String, Object> set = propertiesToSet;
116117
public final String[] unset = propertiesToUnset;
@@ -297,7 +298,7 @@ public CompletableFuture<Response> updateActivityToTargets(Token token, FeedID f
297298
try {
298299
final byte[] payload = toJSON(new Object() {
299300
public String foreign_id = activity.getForeignID();
300-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
301+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", lenient = OptBoolean.FALSE, timezone = "UTC")
301302
public Date time = activity.getTime();
302303
public String[] added_targets = addedTargets;
303304
public String[] removed_targets = removedTargets;

src/main/java/io/getstream/core/models/Activity.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.google.common.base.MoreObjects;
88
import com.google.common.collect.Lists;
99
import com.google.common.collect.Maps;
10+
import io.getstream.core.models.serialization.DateDeserializer;
1011

1112
import java.util.Date;
1213
import java.util.List;
@@ -71,7 +72,7 @@ public String getTarget() {
7172
return target;
7273
}
7374

74-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
75+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", lenient = OptBoolean.FALSE, timezone = "UTC")
7576
public Date getTime() {
7677
return time;
7778
}
@@ -182,7 +183,7 @@ public Builder target(String target) {
182183
return this;
183184
}
184185

185-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
186+
@JsonDeserialize(using = DateDeserializer.class)
186187
public Builder time(Date time) {
187188
this.time = time;
188189
return this;

src/main/java/io/getstream/core/models/EnrichedActivity.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.google.common.base.MoreObjects;
88
import com.google.common.collect.Lists;
99
import com.google.common.collect.Maps;
10+
import io.getstream.core.models.serialization.DateDeserializer;
1011

1112
import java.util.Date;
1213
import java.util.List;
@@ -78,7 +79,7 @@ public Data getTarget() {
7879
return target;
7980
}
8081

81-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
82+
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS", lenient = OptBoolean.FALSE, timezone = "UTC")
8283
public Date getTime() {
8384
return time;
8485
}
@@ -231,7 +232,7 @@ public Builder target(Data target) {
231232
return this;
232233
}
233234

234-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
235+
@JsonDeserialize(using = DateDeserializer.class)
235236
public Builder time(Date time) {
236237
this.time = time;
237238
return this;

src/main/java/io/getstream/core/models/Group.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package io.getstream.core.models;
22

33
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonFormat;
54
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
65
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
77
import com.google.common.base.MoreObjects;
8+
import io.getstream.core.models.serialization.DateDeserializer;
89

910
import java.util.Date;
1011
import java.util.List;
@@ -29,10 +30,10 @@ public Group(
2930
@JsonProperty("actor_count")
3031
int actorCount,
3132
@JsonProperty("created_at")
32-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
33+
@JsonDeserialize(using = DateDeserializer.class)
3334
Date createdAt,
3435
@JsonProperty("updated_at")
35-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
36+
@JsonDeserialize(using = DateDeserializer.class)
3637
Date updatedAt) {
3738
checkNotNull(group, "Group 'group' field required");
3839
checkNotNull(activities, "Group 'activities' field required");

src/main/java/io/getstream/core/models/NotificationGroup.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package io.getstream.core.models;
22

33
import com.fasterxml.jackson.annotation.JsonCreator;
4-
import com.fasterxml.jackson.annotation.JsonFormat;
54
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
65
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
77
import com.google.common.base.MoreObjects;
8+
import io.getstream.core.models.serialization.DateDeserializer;
89

910
import java.util.Date;
1011
import java.util.List;
@@ -24,10 +25,10 @@ public NotificationGroup(
2425
@JsonProperty("actor_count")
2526
int actorCount,
2627
@JsonProperty("created_at")
27-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
28+
@JsonDeserialize(using = DateDeserializer.class)
2829
Date createdAt,
2930
@JsonProperty("updated_at")
30-
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.S", timezone = "UTC")
31+
@JsonDeserialize(using = DateDeserializer.class)
3132
Date updatedAt,
3233
@JsonProperty("is_seen")
3334
boolean isSeen,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.getstream.core.models.serialization;
2+
3+
import com.fasterxml.jackson.core.JsonParser;
4+
import com.fasterxml.jackson.core.JsonProcessingException;
5+
import com.fasterxml.jackson.databind.DeserializationContext;
6+
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
7+
8+
import java.io.IOException;
9+
import java.text.ParseException;
10+
import java.text.SimpleDateFormat;
11+
import java.util.Date;
12+
import java.util.TimeZone;
13+
14+
public class DateDeserializer extends StdDeserializer<Date> {
15+
private static final String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS";
16+
private static final int allowedLength = pattern.length() - 2; // don't include 2 single quotes
17+
18+
public DateDeserializer() {
19+
super(Date.class);
20+
}
21+
22+
@Override
23+
public Date deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
24+
SimpleDateFormat formatter = new SimpleDateFormat(pattern);
25+
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
26+
formatter.setLenient(false);
27+
28+
String date = parser.getValueAsString();
29+
// trim if date includes microseconds
30+
if (date.length() > allowedLength) {
31+
date = date.substring(0, allowedLength);
32+
}
33+
try {
34+
return formatter.parse(date);
35+
} catch (ParseException e) {
36+
throw context.weirdStringException(parser.getValueAsString(), Date.class, "Could not deserialize Date using '" + pattern + "' pattern");
37+
}
38+
}
39+
}

src/test/java/io/getstream/core/utils/SerializationTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,11 @@ void anyGetterConversion() {
143143

144144
@Test
145145
void activityDeserialization() throws ParseException {
146-
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");
146+
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
147147
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
148148

149149
Activity[] result = new Activity[1];
150-
String activity = "{\"actor\":\"test\",\"verb\":\"test\",\"object\":\"test\",\"time\":\"2001-09-11T00:01:02.000000\",\"to\":[\"hey:now\"]}";
150+
String activity = "{\"actor\":\"test\",\"verb\":\"test\",\"object\":\"test\",\"time\":\"2019-01-10T15:08:53.442419\",\"to\":[\"hey:now\"]}";
151151

152152
assertDoesNotThrow(() -> {
153153
result[0] = fromJSON(new ByteArrayInputStream(activity.getBytes(Charset.forName("UTF-8"))), Activity.class);
@@ -156,7 +156,7 @@ void activityDeserialization() throws ParseException {
156156
assertEquals(result[0].getVerb(), "test");
157157
assertEquals(result[0].getObject(), "test");
158158
assertEquals(result[0].getTo(), Lists.newArrayList(new FeedID("hey:now")));
159-
assertEquals(result[0].getTime(), isoFormat.parse("2001-09-11T00:01:02.000000"));
159+
assertEquals(result[0].getTime(), isoFormat.parse("2019-01-10T15:08:53.442"));
160160
}
161161

162162
@Test

0 commit comments

Comments
 (0)