I'm trying to serialize/deserialize the DynamoDB V2 AttributeValue class using Jackson.
It is setup as an immutable class with a Builder and the builder has a private constructor. In order to create a builder, you need to call AttributeValue.builder()
.
I have no control over this class, so I want to use Jackson mixins.
I've used the @JsonDeserialize(builder = AttributeValue.Builder::class)
and registered the mixin:
@JsonDeserialize(builder = AttributeValue.Builder::class)
interface AttributeValueMixin {
}
private val mapper = jacksonObjectMapper()
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
.addMixIn(AttributeValue::class.java, AttributeValueMixin::class.java)
However, Jackson is trying to use the default constructor of the AttributeValue.Builder
and it can't since it doesn't have one.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of
software.amazon.awssdk.services.dynamodb.model.AttributeValue$Builder
(no Creators, like default construct, exist)
How can I get Jackson to use the AttributeValue.builder()
factory function? Or any other ideas on how to use Jackson to serialize/deserialize this AttributeValue
class?
So this feels totally jankey, but it works, so... ¯\(ツ)/¯
For my case, I needed to seralize/deseralize a Map<String, AttributeValue>
, so I used a technique of stuffing the JSON version of the map into a "map" attribute, deserializing, and then extracting the "map" value:
import com.fasterxml.jackson.databind.ObjectMapper
// the Jackson mapper
val mapper = ObjectMapper()
// I don't remember if this was needed, but I assume so...
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY)
// This is probably just to make the JSON smaller
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
// to JSON
val dynamoAttributes: Map<String, AttributeValue> = ...
val attributesAsJson = mapper.writeValueAsString(dynamoAttributes)
// read back from JSON
val result: Map<String, AttributeValue> =
mapper.readValue(
"""{"m":$attributesAsJson}""", // stuff the JSON into a map field
AttributeValue.serializableBuilderClass())
.build()
.m() // extract the "strongly" typed map