使用Jackson反序列化非字符串Map键

zbdgwd5y  于 2022-11-08  发布在  其他
关注(0)|答案(5)|浏览(317)

我有一张Map,看起来像这样:

public class VerbResult {
    @JsonProperty("similarVerbs")
    private Map<Verb, List<Verb>> similarVerbs;
}

我的动词类看起来像这样:

public class Verb extends Word {
    @JsonCreator
    public Verb(@JsonProperty("start") int start, @JsonProperty("length") int length,
            @JsonProperty("type") String type, @JsonProperty("value") VerbInfo value) {
        super(length, length, type, value);
    }
    //...
}

我想序列化和反序列化VerbResult类的示例,但是当我这样做时,我得到以下错误:Can not find a (Map) Key deserializer for type [simple type, class my.package.Verb]
我在网上看到你需要告诉Jackson如何反序列化map键,但是我没有找到任何解释如何去做的信息。动词类也需要在map之外被序列化和反序列化,所以任何解决方案都应该保留这个功能。
谢谢你的帮助。

ejk8hzay

ejk8hzay1#

经过 一 天 的 搜索 , 我 找到 了 一 种 基于 this question 的 更 简单 的 方法 , 解决 方案 是 将 @JsonDeserialize(keyUsing = YourCustomDeserializer.class) 注解 添加 到 Map 中 , 然后 通过 扩展 KeyDeserializer 实现 自 定义 反 序列 化 器 , 并 重写 deserializeKey 方法 , 该 方法 将 使用 字符 串 键 调用 , 您 可以 使用 该 字符 串 构建 真正 的 对象 ,或者 甚至 从 数据 库 中 取出 现有 的 一 个 。
所以 首先 在 Map 上 声明 :

@JsonDeserialize(keyUsing = MyCustomDeserializer.class)
private Map<Verb, List<Verb>> similarVerbs;

中 的 每 一 个
然后 创建 将 使用 字符 串 键 调用 的 反 序列 化 程序 。

public class MyCustomDeserializer extends KeyDeserializer {
    @Override
    public MyMapKey deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        //Use the string key here to return a real map key object
        return mapKey;
    }
}

格式
适用 于 Jersey 和 Jackson 2.x

zzzyeukh

zzzyeukh2#

如上所述,技巧是需要一个key反序列化器(这也让我感到困惑)。在我的例子中,在我的类上配置了一个非StringMap键,但它不在我正在解析的JSON中,所以一个非常简单的解决方案对我来说是有效的(只需在键反序列化器中返回null)。

public class ExampleClassKeyDeserializer extends KeyDeserializer
{
    @Override
    public Object deserializeKey( final String key,
                                  final DeserializationContext ctxt )
       throws IOException, JsonProcessingException
    {
        return null;
    }
}

public class ExampleJacksonModule extends SimpleModule
{
    public ExampleJacksonModule()
    {
        addKeyDeserializer(
            ExampleClass.class,
            new ExampleClassKeyDeserializer() );
    }
}

final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule( new ExampleJacksonModule() );
sgtfey8w

sgtfey8w3#

构建在answer given here上,它建议使用反序列化程序实现一个模块。JodaTime Module是一个包含序列化程序和反序列化程序的模块的完整示例,易于理解。
请注意,模块功能是在Jackson1.7版中引入的,因此您可能需要升级。
所以一步一步:
1.根据Joda示例为类创建一个包含序列化程序(反序列化程序)的模块
1.使用mapper.registerModule(module);注册模块
然后你就可以

soat7uwm

soat7uwm4#

在浏览了网络之后,我想我有一个关于如何处理POJO风格的键的不错的解决方案(尽管,一如既往,最好不要使用完整的对象作为Map键)。
串行器(注册为Jackson模块,位于Sping Boot 内部):

@Bean
fun addKeySerializer(): Module =
    SimpleModule().addKeySerializer(YourClass::class.java, YourClassSerializer())

class YourClassSerializer() : JsonSerializer<YourClass>() {
    override fun serialize(value: DataElement, gen: JsonGenerator, serializers: SerializerProvider) {
        gen.writeFieldName(jacksonObjectMapper().writeValueAsString(value))
    }
}

(note在标准Java环境中,您必须在此处示例化您自己的objectMapper示例)
解串器:

@Bean
fun addKeyDeserializer(): Module =
    SimpleModule().addKeyDeserializer(YourClass::class.java, YourClassDeserializer())

class YourClassDeserializer() : KeyDeserializer() {
    override fun deserializeKey(key: String, ctxt: DeserializationContext): YourClass? {
        return ctxt.parser.readValueAs(YourClass::class.java)
    }
}
gz5pxeao

gz5pxeao5#

假设我们有一个Map属性,如下所示:

class MyDTO{
    @JsonSerialize(keyUsing = MyObjectKeySerializer.class)
    @JsonDeserialize(keyUsing = MyObjectKeyDeserilazer.class)
    private Map<MyObjectKey , List<?>> map;
}

我们将MyObjectKey序列化为json字符串,调用objectMapper.writeAsString;并从json字符串反序列化到MyObjectKey

public class MyObjectKeySerializer extends StdSerializer<MyObjectKey> {

        public Serializer() {
            super(MyObjectKey.class);
        }

        @Override
        public void serialize(MyObjectKey value, JsonGenerator gen, SerializerProvider provider) throws IOException {
            gen.writeFieldName(JsonUtil.toJSONString(value));
        }
    }

    public class MyObjectKeyDeserilazer extends KeyDeserializer {
        @Override
        public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException {
            return JsonUtil.toObject(key, MyObjectKey.class);
        }
    }

相关问题