java.util.BitSet
是个非常方便的比特位数据存储和操作类,一个 bit 具有2个值:0和1,正好可以用来表示 false 和 true,适用于判断“数据是否存在”的场景。
但是,这个从JDK1.0版本就存在的类,Jackson,Fastjson这些主流的JSON工具却并没有对它提供序列化和反序列化支持。
所以如果要在自己的数据结构中用到BitSet,就要自己实现序列化和反序列化。
上篇博客《java:java.util.BitSet对象的Fastjson序列化和反序列化实现》介绍了Fastjson实现,本文说明Jackson如何支持BitSet类型的序列化和反序列化
以下是BitSet对象的Jackson序列化和反序列化实现,
主要思路就是在序列化过程中将BitSet的数据转为JSON数组(如[7707,8822]
或单个数字(当设置SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED
特性时).
在反序列化阶段,根据TOKEN类型不同,将数据序列化为long[]
再调用BitSet.valueOf
方法转为BitSet对象返回。
/**
* {@link BitSet} 的JACKSON序列化和反序列化实现
* @author guyadong
* @since 3.30.1
*/
public class BitSetJacksonCodec{
public static final Deserializer DESERIALIZER = new Deserializer();
public static final Serializer SERIALIZER = new Serializer();
/**
* {@link BitSet}反序列化实现
*/
public static class Deserializer extends JsonDeserializer<BitSet> {
private final JsonDeserializer<?> longArrayDeserializer = PrimitiveArrayDeserializers.forType(long.class);
@Override
public BitSet deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
switch(jp.currentTokenId()) {
case JsonTokenId.ID_NULL:
jp.nextToken();
return null;
case JsonTokenId.ID_START_ARRAY:{
long[] longs = (long[]) longArrayDeserializer.deserialize(jp, ctxt);
return BitSet.valueOf(longs);
}
case JsonTokenId.ID_STRING:{
/** 将文本递归解析 */
String text = jp.getText();
jp.nextToken();
return mapper.readValue(text, BitSet.class);
}
default:{
/** 数字类型:VALUE_NUMBER_INT */
BitSet bitSet = BitSet.valueOf(new long[] {jp.getNumberValue().longValue()});
jp.nextToken();
return bitSet;
}
}
}
}
/**
* {@link BitSet}序列化实现
*/
public static class Serializer extends JsonSerializer<BitSet> {
@SuppressWarnings({ "rawtypes" })
private final JsonSerializer longArraySerializer = StdArraySerializers.findStandardImpl(long[].class);
@SuppressWarnings("unchecked")
@Override
public void serialize(BitSet value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
if(null == value) {
gen.writeNull();
}else {
longArraySerializer.serialize(value.toLongArray(), gen, serializers);
}
}
}
}
测试及调用示例:
@Test
public void test5JacksonCodec() {
try {
BitSet bitSet = BitSet.valueOf(new byte[] {27,30});
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule()
.addDeserializer(BitSet.class, BitsetJacksonCodec.DESERIALIZER)
.addSerializer(BitSet.class, BitsetJacksonCodec.SERIALIZER);
mapper.registerModule(module);
{
/** 序列化为数组 */
String json = mapper.writeValueAsString(bitSet);
log("JSON:{}",json);
assertTrue(json.equals("[7707]"));
BitSet parsed = mapper.readValue(json, BitSet.class);
assertTrue(bitSet.equals(parsed));
}
{
mapper.enable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
/** 序列化为数字 */
String json = mapper.writeValueAsString(bitSet);
log("JSON:{}",json);
assertTrue(json.equals("7707"));
BitSet parsed = mapper.readValue(json, BitSet.class);
assertTrue(bitSet.equals(parsed));
}
{
mapper.disable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
/** 序列化为数字 */
String json = mapper.writeValueAsString(new TestBean(bitSet, 32));
log("JSON:{}",json);
assertTrue(json.equals("{\"bitSet\":[7707],\"age\":32}"));
TestBean parsed = mapper.readValue(json, TestBean.class);
assertTrue(bitSet.equals(parsed.bitSet));
}
}catch (Throwable e) {
e.printStackTrace();
fail();
}
}
public static class TestBean{
BitSet bitSet;
Integer age;
public TestBean() {
}
public TestBean(BitSet bitSet, Integer age) {
this.bitSet = bitSet;
this.age = age;
}
public BitSet getBitSet() {
return bitSet;
}
public void setBitSet(BitSet bitSet) {
this.bitSet = bitSet;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
完整实现代码参见码云仓库:https://gitee.com/l0km/sql2java/blob/dev/sql2java-base/src/main/java/gu/sql2java/json/BitSetJacksonCodec.java
完整测试代码参见码云仓库:https://gitee.com/l0km/sql2java/blob/dev/sql2java-base/src/test/java/gu/sql2java/BitSetJsonCodecTest.java