我有Range
我需要以某种格式序列化,即"[lower,upper)"
。为此,我编写了一个基本的序列化器:
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 :(得分: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)"'
}
}