java 将Jackson与不可变的AWS V2 DDB AttributeValue与私有构建器一起使用?

jjjwad0x  于 2023-04-28  发布在  Java
关注(0)|答案(3)|浏览(103)

我正在尝试使用Jackson序列化/反序列化DynamoDB V2 AttributeValue类。
它被设置为一个具有Builder的不可变类,并且Builder有一个私有构造函数。为了创建一个构建器,需要调用AttributeValue.builder()
我无法控制这个类,所以我想使用Jacksonmixins。
我使用了@JsonDeserialize(builder = AttributeValue.Builder::class)并注册了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)

但是,Jackson试图使用AttributeValue.Builder的默认构造函数,但由于没有,因此无法使用。
com.fasterxml.jackson.databind.exc.InvalidDefinitionException:无法构造software.amazon.awssdk.services.dynamodb.model.AttributeValue$Builder的示例(不存在创建者,如默认构造)
如何让Jackson使用AttributeValue.builder()工厂函数?关于如何使用Jackson来序列化/反序列化这个AttributeValue类,有什么其他想法吗?

uujelgoq

uujelgoq1#

确实很棘手我能想到两个解决办法:
1.在原始构建器周围创建 Package :

class BuilderDelegate {

    var field1 : String? = null
    var field2 : String? = null
    ...

    fun build() = AttributeValue.builder().also {
        it.field1 = field1
        it.field2 = field2
        ...
    }.build()
}

@JsonDeserialize(builder = BuilderDelegate::class)
interface AttributeValueMixin {
}

1.如果你是直接调用对象Map器,你可以尝试以下技巧:

val builder = mapper.readerForUpdating(AttributeValue.builder())
val value = builder.readValue<AttributeValue.Builder>(jsonData).build()
zaq34kh6

zaq34kh62#

所以这感觉完全是垃圾,但它的工作,所以。.. ¯*()*/¯
在我的例子中,我需要序列化/沙漠化一个Map<String, AttributeValue>,所以我使用了一种技术,将Map的JSON版本填充到一个“map”属性中,反序列化,然后提取“map”值:

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
mgdq6dx1

mgdq6dx13#

请看我对这个问题的回答:https://stackoverflow.com/a/65603336/2288986

摘要

首先是一个helper方法:

static ValueInstantiator createDefaultValueInstantiator(DeserializationConfig config, JavaType valueType, Supplier<?> creator) {
    class Instantiator extends StdValueInstantiator {
        public Instantiator(DeserializationConfig config, JavaType valueType) {
            super(config, valueType);
        }

        @Override
        public boolean canCreateUsingDefault() {
            return true;
        }

        @Override
        public Object createUsingDefault(DeserializationContext ctxt) {
            return creator.get();
        }
    }

    return new Instantiator(config, valueType);
}

然后为你的类添加ValueInstantiator

var mapper = new ObjectMapper();
var module = new SimpleModule()
        .addValueInstantiator(
                AttributeValue.Builder.class,
                createDefaultValueInstantiator(
                        mapper.getDeserializationConfig(),
                        mapper.getTypeFactory().constructType(AttributeValue.Builder.class),
                        AttributeValue::builder
                )
        );

mapper.registerModule(module);

现在Jackson将能够示例化AttributeValue.Builder

相关问题