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);