Не удается найти десериализатор (Map) Key для типа [простой тип, класс]

У меня есть объект домена с картой:

private Map<AutoHandlingSlotKey, LinkedHashSet<AutoFunction>> autoHandling;

Когда я сериализую объект, я получаю следующее:

"autoHandling" : [ "java.util.HashMap", {
} ],

Ключ этой карты является настраиваемым объектом:

public class AutoHandlingSlotKey implements Serializable {
    private FunctionalArea slot; // ENUM
    private String returnView;   // ENUM

Итак, я не уверен, как исправить это исключение, которое я получаю при десериализации объекта:

org.codehaus.jackson.map.JsonMappingException: Can not find a (Map) Key deserializer for type [simple type, class com.comcast.ivr.core.domain.AutoHandlingSlotKey]

Как исправить эту проблему? У меня нет доступа к объекту домена, который нужно изменить.


person Mick Knutson    schedule 16.06.2011    source источник
comment
Относительно 2.9 и потенциально других версий: я понимаю проблему github.com/FasterXML/jackson-databind / issues / 1419, например Map, сериализация с аннотированными свойствами просто не работает, и Джексон выдает несвязанное сообщение об ошибке.   -  person Karl Richter    schedule 11.03.2018


Ответы (2)


По умолчанию Джексон пытается сериализовать Java-карты как объекты JSON (пары ключ / значение), поэтому ключевой объект Map должен быть каким-то образом сериализован как String; и должен быть соответствующий (и зарегистрированный) десериализатор ключей. Конфигурация по умолчанию поддерживает только небольшой набор типов JDK (String, numbers, enum). Таким образом, mapper не знает, как взять String и создать из него AutoHandlingSlotKey. (на самом деле я удивлен, что сериализатор не отказал по той же причине)

Два очевидных способа решить эту проблему:

  • Внедрить и зарегистрировать «ключевой десериализатор»
  • Внедрите и зарегистрируйте специальный десериализатор для карт.

В вашем случае, наверное, проще сделать первое. Вы также можете реализовать собственный сериализатор ключей, чтобы обеспечить сериализатор ключей в правильном формате.

Самый простой способ зарегистрировать сериализаторы и десериализаторы - это интерфейс модуля, который был добавлен в Jackson 1.7 (и расширен в 1.8 для поддержки сериализаторов / десериализаторов ключей).

person StaxMan    schedule 16.06.2011
comment
После быстрого теста я думаю, что ключи сериализуются с использованием их метода toString, что, вероятно, часто не то, что вам нужно. Создание сериализатора ключей кажется хорошим вариантом. - person Suma; 14.07.2015
comment
Это запасной вариант, если больше ничего не найдено. Есть альтернативы: например, если у типа есть общедоступный конструктор с одним строковым аргументом, который будет использоваться. Или фабричный метод с одним строковым аргументом, помеченный знаком @JsonCreator. Это избавит от необходимости писать и регистрировать специальный десериализатор ключей. - person StaxMan; 15.07.2015
comment
Отлично, но вы описываете десериализатор (я его попробую). А как насчет сериализатора? В моем случае использовался toString (для класса кейсов Scala). Какие еще есть варианты сериализатора, кроме написания собственного? - person Suma; 15.07.2015
comment
Правильно, для сериализатора использование @JsonValue должно работать, хотя я это не тестировал; есть некоторые пробелы в поддержке аннотаций с ключевыми (де) сериализаторами. Помимо этого, настраиваемый сериализатор ключей - это вариант, который можно либо зарегистрировать глобально, либо использовать @JsonSerialize(keyUsing=MyKeySerializer.class для класса или свойства. - person StaxMan; 17.07.2015

Этот вопрос был задан давно, и это первый результат Google при поиске ошибки, но принятый ответ не имеет кода и может сбить с толку новичка Джексона (меня). В конце концов я нашел этот ответ, который помог.

Итак, как указано в принятом ответе, реализация и регистрация «десериализатора ключей» - это правильный путь. Сделать это можно вот так.

SimpleModule simpleModule = new SimpleModule();
simpleModule.addKeyDeserializer(YourClass.class, new YourClassKeyDeserializer());
objectMapper.registerModule(simpleModule);

А для класса все, что вам нужно сделать, это:

class YourClassKeyDeserializer extends KeyDeserializer
{
    @Override
    public Object deserializeKey(final String key, final DeserializationContext ctxt ) throws IOException, JsonProcessingException
    {
        return null; // replace null with your logic
    }
}

Вот и все! Нет аннотаций к классам, нет настраиваемого десериализатора для карт и т. Д.

person estebanrv    schedule 26.05.2017
comment
Вы знаете, как зарегистрировать модуль в контексте Resteasy, загруженном через Spring? Я не знаю, как получить доступ к автоматически созданному objectMapper - person Fractaliste; 20.06.2018
comment
@Fractaliste, это уже другой вопрос. Но вкратце: вы заменяете это своим собственным bean-компонентом. @Bean fun myMapper(): ObjectMapper { ... } - person Ondra Žižka; 28.01.2021
comment
Что делать, если ключ - это другой объект, хранящийся в формате JSON? Могу ли я безопасно использовать преобразователь, созданный в моем десериализаторе ключей? - person Ondra Žižka; 28.01.2021