I am working on a AWS lambda function in order to get dynamically a SNS Event or a Kinesis Event, to do so, in my lambda function I am getting an Object as parameter:
@Override
public GatewayResponse handleRequest(final Object object, Context context)
Then, I am using Jackson in order to convert it to SNS or Kinesis dynamically:
public static SNSEvent convertObjectToSNSEvent(Object object) {
return objectMapper.convertValue(object, SNSEvent.class);
}
public static KinesisEvent convertToKinesisEvent(Object object) {
return objectMapper.convertValue(object, KinesisEvent.class);
}
The problem is that, when I’m using the convertToKinesisEvent
function I am getting:
java.lang.IllegalArgumentException: Cannot deserialize instance of `java.util.Date` out of VALUE_NUMBER_FLOAT token
SNSEvent convertion works fine, but Kinesis does not, I have realized that is because in the Kinesis Json, the time stamp (approximateArrivalTimestamp field) is represented with decimals:
{
"Records": [
{
"kinesis": {
"partitionKey": "partitionKey-03",
"kinesisSchemaVersion": "1.0",
"data": "eyJpZCI6MjY2MjU4NSwiZGVzY3JpcHRpb24iOiJUZXN0IFBheWxvYWQifQ==",
"sequenceNumber": "49545115243490985018280067714973144582180062593244200961",
"approximateArrivalTimestamp": 1.57538737506E9
},
"eventSource": "aws:kinesis",
"eventID": "shardId-000000000000:49545115243490985018280067714973144582180062593244200961",
"invokeIdentityArn": "arn:aws:iam::EXAMPLE",
"eventVersion": "1.0",
"eventName": "aws:kinesis:record",
"eventSourceARN": "arn:aws:kinesis:EXAMPLE",
"awsRegion": "us-east-1"
}
]
}
If I execute the same code with a integer in the timestamp it works fine:
{
"Records": [
{
"kinesis": {
"partitionKey": "partitionKey-03",
"kinesisSchemaVersion": "1.0",
"data": "eyJpZCI6MjY2MjU4NSwiZGVzY3JpcHRpb24iOiJUZXN0IFBheWxvYWQifQ==",
"sequenceNumber": "49545115243490985018280067714973144582180062593244200961",
"approximateArrivalTimestamp": 11234432432
},
"eventSource": "aws:kinesis",
"eventID": "shardId-000000000000:49545115243490985018280067714973144582180062593244200961",
"invokeIdentityArn": "arn:aws:iam::EXAMPLE",
"eventVersion": "1.0",
"eventName": "aws:kinesis:record",
"eventSourceARN": "arn:aws:kinesis:EXAMPLE",
"awsRegion": "us-east-1"
}
]
}
Here is the full error log:
java.lang.IllegalArgumentException: Cannot deserialize instance of `java.util.Date` out of VALUE_NUMBER_FLOAT token
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.amazonaws.services.lambda.runtime.events.KinesisEvent["Records"]->java.util.ArrayList[0]->com.amazonaws.services.lambda.runtime.events.KinesisEvent$KinesisEventRecord["kinesis"]->com.amazonaws.services.lambda.runtime.events.KinesisEvent$Record["approximateArrivalTimestamp"])
at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:3922)
at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:3853)
at util.JsonUtil.convertToKinesisEvent(JsonUtil.java:28)
at pojos.RecordsHandler.getMessages(RecordsHandler.java:38)
at handler.App.handleRequest(App.java:41)
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:498)
at lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:261)
at lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:178)
at lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:906)
at lambdainternal.AWSLambda.startRuntime(AWSLambda.java:341)
at lambdainternal.AWSLambda.<clinit>(AWSLambda.java:63)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:114)
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.Date` out of VALUE_NUMBER_FLOAT token
Does someone know what is happening?
–Update– Dependencies:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit -->
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>retrofit</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>com.squareup.retrofit2</groupId>
<artifactId>converter-jackson</artifactId>
<version>2.6.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.10.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-joda -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-lambda-java-events -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>2.2.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.11.685</version>
</dependency>
</dependencies>
Thanks
Advertisement
Answer
Ok, so what I ended up doing was to add my custom deserializer to Jackson in order to solve the problem:
public class TimestampDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(jsonParser.getValueAsLong());
return calendar.getTime();
}
}
And then add a custom serializer
public class TimestampSerializer extends JsonSerializer<Date> {
@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(date.toString());
}
}
And then add it to Jackson and it worked, I don’t know if there is another solution but It achieve my goal
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new TimestampSerializer());
module.addDeserializer(Date.class, new TimestampDeserializer());
objectMapper.registerModule(module);