上一篇博客,介绍了关于Jackson 自定义序列化 ,本文将介绍关于 Jackson 自定义反序列化。
反序列化,Jackson 工具包中已经支持了开发中常用的 Java 类型的解析功能;但是还是会遇到一些我们需要自定义的解析转换工作。比如外部的一些非主流时间格式转换,再比如说对于一些类型转换,做一些额外数据校验和默认容错处理工作,再比如说前端的某种格式的字符串,我们想直接使用自定义反序列化类来完成到 Java Object 的转换工作等等,都需要我们去自己实现 Jackson 反序列化类。
和Jackson 自定义序列化
相似,Jackson 为自定义的反序列化扩展,也提供了简单易用的接口。
在 Jackson 自定义序列化中提供了两种接口,但是在反序列的时候,只有一个接口使用。不过,和序列化一样,反序列化的扩展也很简单,接口为:org.codehaus.jackson.map.JsonDeserializer
,Jackson还提供了一个通用的扩展子类com.fasterxml.jackson.databind.deser.std.StdDeserializer
。
一般,我们可以直接继承JsonDeserializer
抽象类就已经足够满足我们的自定义反序列化需求了。
JsonDeserializer 接口 和序列化很像,这里我们也只需要实现一个反序列化方法deserialize
就足够了。当然,如果你有其他的更高的需求,可以进一步 override 其他的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public abstract class JsonDeserializer <T > { public abstract T deserialize (JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException ; public T deserialize (JsonParser jp, DeserializationContext ctxt, T intoValue) throws IOException, JsonProcessingException { throw new UnsupportedOperationException("Can not update object of type " +intoValue.getClass().getName()+" (by deserializer of type " +getClass().getName()+")" ); } @SuppressWarnings("unchecked") public Object deserializeWithType (JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException, JsonProcessingException { return (T) typeDeserializer.deserializeTypedFromAny(jp, ctxt); } }
Tips:这个反序列化方法实现起来很简单,只需要实现核心的deserialize
方法,使用jp.getText
获取 value 然后对字符串进行我们需要的各种操作转换,赋值给创建的对象实例,就 OK 了。
和序列化一样,Jackson 也提供了三种方法来注册到 ObjectMapper
上。根据官方推荐,这里只介绍两种方式:
SimpleModule 类注册 SimpleModule
类是1.8版本才提供的注册类,当我们想在全局的反序列环境下,对指定类型的每一次反序列化都会按照这个类方法进行解析,就可以在SimpleModule
中添加指定的自定义反序列类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class SimpleModule extends Module { protected final String _name; protected final Version _version; protected SimpleSerializers _serializers = null ; protected SimpleDeserializers _deserializers = null ; public <T> SimpleModule addDeserializer (Class<T> type, JsonDeserializer<? extends T> deser) { if (_deserializers == null ) { _deserializers = new SimpleDeserializers(); } _deserializers.addDeserializer(type, deser); return this ; } public SimpleModule addKeyDeserializer (Class<?> type, KeyDeserializer deser) { if (_keyDeserializers == null ) { _keyDeserializers = new SimpleKeyDeserializers(); } _keyDeserializers.addDeserializer(type, deser); return this ; } }
Tips:显然,我们在objectMapper.registerModule
中注册构造的simpleModule对象实例,这个实例调用addDeserializer
把我们自定义的反序列化方法添加进去就可以了。
@JsonDeserialize 注解 使用注解的方式来注册自定义的反序列化方法,可以把自定义粒度控制到某一个类型对象属性上,但是这对于想全局反序列化某个类型,这种方式都会很繁琐。
@JsonDeserialize
和序列化注解,完全一样。使用方式如下:
1 2 3 4 5 6 @JsonDeserialize(using = CustomizeJsonDeserializer.class) public void setB (TypeB b) { this .b = b; }
和 Jackson 自定义序列化一样,这里主要把实现继承反序列化接口的代码和 mapper 注册贴出来,参考下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class CustomizeJsonDeserializer extends JsonDeserializer <TypeB > { @Override public TypeB deserialize (JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { String value = jp.getText(); Map<String, String> properities = Splitter.on("," ).trimResults().withKeyValueSeparator("=" ).split(StringUtils.substringBetween(value, "{" , "}" )); System.out.println(JsonUtils.encode(properities)); TypeB typeB = new TypeB(properities.get("address" ), Integer.valueOf(properities.get("code" ))); return typeB; } } public class JsonUtils { private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class); public final static ObjectMapper objectMapper = new ObjectMapper(); static { objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true ); objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true ); objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true ); objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true ); objectMapper.configure(JsonParser.Feature.INTERN_FIELD_NAMES, true ); objectMapper.configure(JsonParser.Feature.CANONICALIZE_FIELD_NAMES, true ); objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false ); objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); } public static <T> T decode (String json, Class<T> valueType) { try { SimpleModule deserializeModule = new SimpleModule("DeserializeModule" , new Version(1 , 0 , 0 , null )); deserializeModule.addDeserializer(TypeB.class,new CustomizeJsonDeserializer()); objectMapper.registerModule(deserializeModule); return objectMapper.readValue(json, valueType); } catch (JsonParseException e) { logger.error("decode(String, Class<T>)" , e); } catch (JsonMappingException e) { logger.error("decode(String, Class<T>)" , e); } catch (IOException e) { logger.error("decode(String, Class<T>)" , e); } return null ; } }