25

我有一张看起来像这样的地图:

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]

我在网上读到你需要告诉杰克逊如何反序列化映射键,但我没有找到任何解释如何去做的信息。动词类也需要在地图之外进行序列化和反序列化,因此任何解决方案都应保留此功能。

感谢您的帮助。

4

4 回答 4

42

经过一天的搜索,我发现了一种基于此问题的更简单的方法。解决方案是将@JsonDeserialize(keyUsing = YourCustomDeserializer.class)注释添加到地图中。然后通过扩展KeyDeserializer和覆盖该deserializeKey方法来实现您的自定义反序列化器。该方法将使用字符串键调用,您可以使用该字符串构建真实对象,甚至从数据库中获取现有对象。

所以首先在地图声明中:

@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

于 2016-07-07T11:47:42.720 回答
13

如上所述,诀窍是您需要一个密钥反序列化器(这也让我感到困惑)。在我的情况下,在我的类上配置了一个非字符串映射键,但它不在我解析的 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() );
于 2014-11-17T21:17:49.113 回答
6

基于此处给出的答案,建议使用反序列化器实现模块。JodaTime模块是一个易于理解的包含序列化器和反序列化器的模块的完整示例。

请注意,模块功能是在 Jackson 1.7 版中引入的,因此您可能需要升级。

所以一步一步:

  1. 根据 Joda 示例为您的类创建一个包含(反)序列化器的模块
  2. 注册该模块mapper.registerModule(module);

你会准备好的

于 2012-06-28T14:41:57.620 回答
0

在网上搜索之后,我认为我对如何处理 POJO 样式的键有一个不错的解决方案(尽管一如既往,最好不要使用完整的对象作为映射键)。

序列化器(注册为 Jackson 模块,在 Spring 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))
    }
}

(请注意,在标准 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)
    }
}
于 2021-10-08T18:16:49.547 回答