2016-08-26 2 views
1

У меня есть Range, что мне нужно сериализовать в определенном формате, а именно "[lower,upper)". Для этого я написал основную сериалайзер:Сериализованный диапазон с Jackson

public class RangeSerializer extends StdSerializer<Range<?>> { 

    @Override 
    public void serialize(final Range<?> value, final JsonGenerator gen, final SerializerProvider provider) throws IOException { 
    if (value != null) { 
     gen.writeRaw('"'); 
     gen.writeRaw('['); 
     provider.defaultSerializeValue(value.lowerEndpoint(), gen); 
     gen.writeRaw(','); 
     provider.defaultSerializeValue(value.upperEndpoint(), gen); 
     gen.writeRaw(')'); 
     gen.writeRaw('"'); 
    } 
    } 

(Обратите внимание, что в действительности сериализатор обрабатывает различные возможности Range, таких как закрытые/открытые диапазоны, возможность неограниченных диапазонов на обоих концах, и т.д., но для в целях моего вопроса, который не имеет значения, поэтому я удалил его, чтобы код был прост).

Моя проблема заключается в том, что, возвращаясь к серийному сериализатору по умолчанию для каждого класса, я заканчиваю кавычками в неправильном месте. Например, если у меня был Range<String> с записью "[foo,bar)", то при ее сериализации я получаю "["foo","bar")". Мне нужен результат без кавычек вокруг значений нижней и верхней конечных точек.

Я понимаю, что дополнительные кавычки связаны с тем, что gen.writeString() в базовом сериализаторе не понимает, что он уже находится в строке. Есть ли способ сообщить генератору об этом или альтернативный способ добиться того, что я пытаюсь сделать?

Обратите внимание, что Range<?> действительно является общим, поэтому я не могу жестко кодировать сериализацию значений. Он должен работать для Range<Integer>, Range<String>, Range<DateTime> и всего остального.

ответ

0

Мне не удалось получить ваш подход к использованию одного генератора для сериализации всего, что работает. Возможно, вы сможете использовать DelegatingJsonGenerator и подключить определенные вызовы, но я решил, что способ, показанный ниже, был значительно проще (ценой незначительной потери производительности).

Это тестовый класс Spock, демонстрирующий, как я смог получить эту работу.

@Grab('com.fasterxml.jackson.core:jackson-databind:2.8.1') 
@Grab('org.spockframework:spock-core:1.0-groovy-2.4') 

import com.fasterxml.jackson.databind.ObjectMapper 
import com.fasterxml.jackson.databind.SerializationFeature 
import com.fasterxml.jackson.databind.annotation.JsonSerialize 
import com.fasterxml.jackson.databind.util.StdConverter 
import spock.lang.Specification 
import spock.lang.Unroll 

class RangeSerializationTest extends Specification { 

    static class Range<T> { 
     T lower 
     T upper 
    } 

    @JsonSerialize(converter = RangeConverter) 
    static interface RangeMixin { 
    } 

    static class RangeConverter extends StdConverter<Range, String> { 
     private static final mapper = new ObjectMapper().disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 

     @Override 
     String convert(Range value) { 
      def lower = mapper.convertValue(value.lower, String) 
      def upper = mapper.convertValue(value.upper, String) 
      return "[$lower,$upper)" 
     } 
    } 


    @Unroll 
    def 'range of #lower.class'() { 
     given: 
     def mapper = new ObjectMapper() 
     mapper.addMixIn(Range, RangeMixin) 

     expect: 
     mapper.writeValueAsString(new Range(lower: lower, upper: upper)) == expectedJson 

     where: 
     lower   | upper   | expectedJson 
     'abc'   | 'def'   | '"[abc,def)"' 
     123   | 456   | '"[123,456)"' 
     new Date(123) | new Date(456) | '"[1970-01-01T00:00:00.123+0000,1970-01-01T00:00:00.456+0000)"' 
    } 
} 
+0

Спасибо за ответ. Конвертер - интересный способ делать что-то, но может ли он быть зарегистрирован так же, как сериализаторы и десериализаторы могут быть зарегистрированы или их нужно прикреплять аннотацией? У меня нет доступа к самому классу Range, и этот диапазон фактически используется в качестве ключа для карты, поэтому я не уверен, что решение на основе аннотаций поможет мне здесь. – jgm

+0

Используйте mixin для добавления аннотации к классу Range. Я отредактировал свой ответ, чтобы показать, как это сделать. Обратите внимание на часть 'addMixin (...)', сконфигурированную на mapper. –

Смежные вопросы