先点赞再看,养成好习惯
前阵子,公司渠道平台对接了一个新渠道,使用 XML 格式的报文交互。虽然 XML 格式有点复杂且“古老”,但好在它功能强大,支持属性、注释,比 JSON 要加的更直观和清晰。java
可是吧,功能强大的同时也有一些弊端。某些复杂的 XML 并不能像 JSON 那样直接和实体类映射,由于 XML 是支持属性(attribute)的,若是一个标签同时拥有多个属性,或者属性和值,就不太好实体类映射了,好比下面这种报文:git
<Root> <extendInfos> <extendInfo key="birthday" value="19870101"/> <extendInfo key="address" value="北京"/> <extendInfo key="gender" value="M"/> <extendInfo key="userName" value="周关"/> </extendInfos> </Root>
像上面这种复杂一点的报文,也是有解决方案的,只是有点不太优雅。好比我能够建立一个 ExtendInfo 类,定义 key/value 两个属性,而后再将 extendInfos 定义为一个 List,也能够完成解析:github
public class Root { private List<ExtendInfo> extendInfos; // getter and setters.... }
但是这个数据格式很明显是个键值对格式,弄个 List 来存储,是否是有点太傻了?要是能用 Map 来接收 extendInfos 的数据该多好……app
Jackson 是个功能很是强大的序列化库,除了支持 JSON 之外,还支持不少其余格式,好比 XML。并且 Jackson 还能够自定义对解析器的加强,经过对
JsonDeserializer
接口的扩展,能够完成更复杂数据的解析:
基于 Jackson,能够定制化一下解析器,来完成上面复杂数据的解析,将 extendInfos 解析为一个 Map,方便程序的处理ide
先定义一个 AttrMap ,用来标记咱们这个特殊的数据类型,直接继承 HashMap 就好:测试
public class AttrMap<K,V> extends HashMap<K,V> { }
接着将 Root 中的类型修改成这个 AttrMap:code
public class Root { private AttrMap<String,Object> extendInfos; // getter and setters.... }
而后是自定义的类型解析器 - AttrMapDeserializer,在这个解析器里将报文和 AttrMap 映射orm
public class AttrMapDeserializer extends JsonDeserializer<AttrMap<String,String>> { @Override public AttrMap<String,String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { JsonToken curToken ; AttrMap<String,String> attrMap = new AttrMap<>(); while ((curToken = p.nextToken()) !=null && curToken.id() == JsonTokenId.ID_FIELD_NAME){ //skip start token p.nextToken(); String key = null,value = null; while ((curToken = p.nextToken()) != null && curToken.id()== JsonTokenId.ID_FIELD_NAME){ String attrName = p.getCurrentName(); String attrValue = p.nextTextValue(); if("key".equals(attrName)){ key = attrValue; } //处理<attr key="any" value="any"/>和<attr key="any">123213</attr>两种形式 if("value".equals(attrName) || "".equals(attrName)){ value = attrValue; } } attrMap.put(key,value); } return attrMap; } }
好了,大功告成,来测试一下:xml
String body = "<Root> \n" + " <extendInfos> \n" + " <extendInfo key=\"birthday\" value=\"19870101\"/> \n" + " <extendInfo key=\"address\" value=\"北京\"/> \n" + " <extendInfo key=\"gender\" value=\"M\"/> \n" + " <extendInfo key=\"userName\" value=\"周关\"/> \n" + " </extendInfos> \n" + "</Root>"; JacksonXmlModule module = new JacksonXmlModule(); module.addDeserializer(AttrMap.class, new AttrMapDeserializer()); ObjectMapper objectMapper = new XmlMapper(module); Root root = objectMapper.readValue(body, Root.class); System.out.println(root); //output Root{extras={birthday=19870101, address=北京, gender=M, userName=周关}}
Jackson XML 模块继承
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.12.2</version> </dependency>
Jackson XML Wiki
https://github.com/FasterXML/...
原创不易,禁止未受权的转载。若是个人文章对您有帮助,就请点赞/收藏/关注鼓励支持一下吧❤❤❤❤❤❤