先点赞再看,养成好习惯

背景

前阵子,公司渠道平台对接了一个新渠道,应用 XML 格局的报文交互。尽管 XML 格局有点简单且“古老”,但好在它功能强大,反对属性、正文,比 JSON 要加的更直观和清晰。

然而吧,功能强大的同时也有一些弊病。某些简单的 XML 并不能像 JSON 那样间接和实体类映射,因为 XML 是反对属性(attribute)的,如果一个标签同时领有多个属性,或者属性和值,就不太好实体类映射了,比方上面这种报文:

<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,也能够实现解析:

public class Root {    private List<ExtendInfo> extendInfos;        // getter and setters....}

可是这个数据格式很显著是个键值对格局,弄个 List 来存储,是不是有点太傻了?要是能用 Map 来接管 extendInfos 的数据该多好……

Jackson 是个性能十分弱小的序列化库,除了反对 JSON 以外,还反对很多其余格局,比方 XML。而且 Jackson 还能够自定义对解析器的加强,通过对 JsonDeserializer 接口的扩大,能够实现更简单数据的解析:

基于 Jackson,能够定制化一下解析器,来实现下面简单数据的解析,将 extendInfos 解析为一个 Map,不便程序的解决

先定义一个 AttrMap ,用来标记咱们这个非凡的数据类型,间接继承 HashMap 就好:

public class AttrMap<K,V> extends HashMap<K,V> {}

接着将 Root 中的类型批改为这个 AttrMap:

public class Root {    private AttrMap<String,Object> extendInfos;        // getter and setters....}

而后是自定义的类型解析器 - AttrMapDeserializer,在这个解析器里将报文和 AttrMap 映射

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;    }}

好了,功败垂成,来测试一下:

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);//outputRoot{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/...

原创不易,禁止未受权的转载。如果我的文章对您有帮忙,就请点赞/珍藏/关注激励反对一下吧❤❤❤❤❤❤