Модули Джексона для сериализации карт

У меня есть класс, который содержит карту (с не строковым ключом) и некоторые другие поля.

public class MyClass() {
    private Map<KeyObject, OtherObject> map;
    private String someField;

    public MyClass(Map<KeyObject, OtherObject> map, String someField) {
        this.map = map;
        this.someField = someField;
    }

    // Getters & Setters
}

Я хотел бы сериализовать и десериализовать этот класс, используя Джексона. Я видел разные способы сделать это и решил попробовать использовать модули Джексона.

Я следил за этим постом и расширил JsonDeserializer и JsonSerializer. Проблема заключается в том, что эти классы должны быть напечатаны, поэтому

public class keyDeserializer extends JsonDeserializer<Map<KeyObject, OtherObject>> {
...
}

То же самое для KeySerializer.

Затем добавляем в модуль:

module.addSerializer(new keySerializer());
module.addDeserializer(Map.class, new keyDeserializer());

Но это неправильно, по-видимому, так как я получаю исключение:

keySerializer does not define valid handledType() -- must either register with method that takes type argument  or make serializer extend 'org.codehaus.jackson.map.ser.std.SerializerBase'

Я мог иметь свой сериализатор и десериализатор для ввода в MyClass, но тогда мне пришлось вручную анализировать все это, что нецелесообразно.

ОБНОВИТЬ:

Мне удалось обойти создание модуля в коде с помощью аннотаций

@JsonDeserialize(using = keyDeserializer.class)
@JsonSerialize(using = keySerializer.class)
private Map<KeyObject, OtherObject> map;

Но затем я должен сериализовать / десериализовать всю структуру карты самостоятельно из вывода toString(). Поэтому попробовал другую аннотацию:

@JsonDeserialize(keyUsing = MyKeyDeserializer.class)
private Map<KeyObject, OtherObject> map;

Где распространяется MyKeyDeserializer org.codehaus.jackson.map.KeyDeserializer и переопределение метода

public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {...}

Затем вручную десериализовать мой ключ, но снова из вывода toString() моего класса ключей.

Это не оптимально (это зависимость от метода toString()). Есть ли способ лучше?

1 ответ

Решение

Закончилось использованием этого сериализатора:

public class MapKeySerializer extends SerializerBase<Object> {
    private static final SerializerBase<Object> DEFAULT = new StdKeySerializer();
    private static final ObjectMapper mapper = new ObjectMapper();

    protected MapKeySerializer() {
    super(Object.class);
    }

    @Override
    public JsonNode getSchema(SerializerProvider provider, Type typeHint) throws JsonMappingException {
    return DEFAULT.getSchema(provider, typeHint);
    }

    @Override
    public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
    if (null == value) {
        throw new JsonGenerationException("Could not serialize object to json, input object to serialize is null");
    }
    StringWriter writer = new StringWriter();
    mapper.writeValue(writer, value);
    jgen.writeFieldName(writer.toString());
    }
}

И этот десериализатор:

public class MapKeyDeserializer extends KeyDeserializer {

    private static final ObjectMapper mapper = new ObjectMapper();

    @Override
    public Object deserializeKey(String key, DeserializationContext ctxt) throws IOException, JsonProcessingException {
    return mapper.readValue(key, MyObject.class);
    }
}

Аннотировал мою карту:

@JsonDeserialize(keyUsing = MapKeyDeserializer.class)
@JsonSerialize(keyUsing = MapKeySerializer.class)
private Map<KeyObject, OtherObject> map;

Это решение, которое сработало для меня, надеюсь, это поможет другим.

Другие вопросы по тегам