将Jackson与不可变的类一起使用Private Builder

问题描述

我正在尝试使用Jackson来对DynamoDB V2 AttributeValue类进行序列化/反序列化。

使用构建器将其设置为不可变的类,并且该构建器具有私有构造函数。为了创建一个构建器,您需要调用AttributeValue.builder()

我对此课程没有控制权,所以我想使用Jackson混音。

我用过@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类进行序列化/反序列化的其他想法?

解决方法

确实很棘手。我可以想到两种解决方案:

  1. 围绕原始构建器创建包装器:
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. 如果您直接调用对象映射器,则可以尝试以下方法:
val builder = mapper.readerForUpdating(AttributeValue.builder())
val value = builder.readValue<AttributeValue.Builder>(jsonData).build()
,

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

总结

首先是一个辅助方法:

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

现在杰克逊将能够实例化一个AttributeValue.Builder

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...