I want to connect to Jackson's deserialization to further deserialize a different JSON document than the one that was provided. This seems like a really weird use case, so let me explain.
I use the Amazon SQS Extended client to post too large messages for SQS on S3 and a message that looks like this: via SQS
["com.amazon.sqs.javamessaging.MessageS3Pointer",{"s3BucketName":"my-bucket","s3Key":"f5a0fa29-7f9c-4852-8bbb-53697799efe2"}]
An extended beanstalk worker listens to the other end of this, which means that these messages are sent to the Jersey endpoint that my application supports. Since these messages are POSTED instead of using the SQS receiveMessage call, the advanced client will not receive the message from S3 itself.
I thought it would be pretty smart to make a custom JsonDeserializer that would look at the message to see if it was an S3 pointer, load this file and deserialize it. Otherwise, just deserialize the provided message. However, this does not work as smoothly as I had hoped.
Here is what I still have:
public class SQSS3Deserializer<T> extends JsonDeserializer<T> { private static final String s3PointerHeader = "com.amazon.sqs.javamessaging.MessageS3Pointer"; private Class<T> type; private ObjectMapper mapper = new ObjectMapper(); public SQSS3Deserializer() { super(); type = getParameterizedTypeArgument(); } @Override public T deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException { if (jp.isExpectedStartArrayToken()) { jp.nextToken(); if (s3PointerHeader.equals(jp.getValueAsString())) { jp.nextToken(); S3Pointer p = jp.readValueAs(S3Pointer.class); return mapper.readValue(S3Utils.getInputStream(p.s3BucketName, p.s3Key), type); } } return jp.readValueAs(type); } @SuppressWarnings("unchecked") protected Class<T> getParameterizedTypeArgument() { return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; } static private class S3Pointer { public String s3BucketName; public String s3Key; } }
For each POJO I want to deserialize, I need to create an empty subclass with the correct general specialization, for example:
public class POJOS3Deserializer extends SQSS3Deserializer<POJO> {}
I will also need to add the JsonDeserializer annotation to the class
@JsonDeserialize(using=POJOS3Deserializer.class) public class POJO { ... }
However, it does throw an error because it will constantly return my deserializer when it calls JsonParser.readValueAs() , because readValueAs looks at the JsonDeserialize annotation.
So, I have two questions:
- How can I change this to keep this pretty general, and yet Jackson does most of the heavy lifting of parsing, avoiding this recursive call?
- Is there a way to remove the need for output from SQSS3Deserializer for each POJO? I want to deserialize this way?
thanks