Модули Джексона для сериализации карт
У меня есть класс, который содержит карту (с не строковым ключом) и некоторые другие поля.
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;
Это решение, которое сработало для меня, надеюсь, это поможет другим.