jackson解析有数组的xml,解析对象不固定的问题


👽个人博客:https://everspring.github.io/
👽公众号:爱历史的IT男

环境

springboot版本2.2.11.RELEASE,jackson version为2.10.0

以下为第一版样例代码,后面XML不会变,ServiceBusReq类的内容会变:

  • 请求体
<TX> 
  <TX_HEADER> 
    <SYS_HDR_LEN/>  
    <SYS_PKG_VRSN>01</SYS_PKG_VRSN>
  </TX_HEADER> 
  <TX_EMB/>  
  <ENTITY> 
    <USER_NAME>xcc</USER_NAME> 
    <COMPANYS>
		<COMPANY>
			<COMPANYNAME>NAME-1</COMPANYNAME>
		</COMPANY>
		<COMPANY>
			<COMPANYNAME>NAME-2</COMPANYNAME>
		</COMPANY>
     </COMPANYS>
  </ENTITY> 
</TX>
  • 实体类
@Data
@JacksonXmlRootElement(localName = "TX")
public class ServiceBusReq<T> {
    @JacksonXmlProperty(localName = "TX_HEADER")
    private ServiceBusHeaderReq txHeader;
    @JacksonXmlProperty(localName = "TX_BODY")
    private ServiceBusBodyReq txBody;
    @JacksonXmlProperty(localName = "TX_EMB")
    private String txEmb;
    @JacksonXmlProperty(localName = "ENTITY")
    private T msgObject;    
}

@Data
@JacksonXmlRootElement(localName = "TX_HEADER")
public class ServiceBusHeaderReq {
    @JacksonXmlProperty(localName = "SYS_HDR_LEN")
    private String sysHdrLen;
}

@RestController
public class ServiceBusController {
	@RequestMapping(method = {RequestMethod.POST},value = "/service",consumes = MediaType.APPLICATION_XML_VALUE)
	public ServiceBusResp xmlService(@RequestBody @Valid ServiceBusReq reqDto) throws ClassNotFoundException {
	   return serviceBusService.invoke(reqDto);
	}
}

@Data
@Builder
public class XmlDemoReqDto {
    @JacksonXmlProperty(localName = "USER_NAME")
    private String UserName;
    @JacksonXmlProperty(localName = "COMPANYS")
    private List<Company> companys;
}

@Data
@JacksonXmlRootElement(localName = "company")
public class Company {
    @JacksonXmlProperty(localName = "COMPANYNAME")
    private String companyName;
}

ServiceBusReq采用的泛型,反序列化ENTITY的对象是不固定的。XmlDemoReqDto 就是ServiceBusReq的泛型对象

问题阶段一

controller中reqDto打印的msgObject类型实际上是一个LinkedHashMap,而LinkedHashMap明显不符合序列化后是个java bean的要求
在这里插入图片描述
解决方法:
添加一个ObjectNode接收,然后把objectNode再转换成msgObject,代码如下:

@Data
@JacksonXmlRootElement(localName = "TX")
public class ServiceBusReq<T> {
    @JacksonXmlProperty(localName = "TX_HEADER")
    private ServiceBusHeaderReq txHeader;
    @JacksonXmlProperty(localName = "TX_BODY")
    private ServiceBusBodyReq txBody;
    @JacksonXmlProperty(localName = "TX_EMB")
    private String txEmb;
    @JacksonXmlProperty(localName = "ENTITY")
    private ObjectNode entity;
    private T msgObject;    
}

/*转换方法*/
private Req convert(ObjectNode entityStr) throws ClassNotFoundException {
        Type[] actualTypeArguments = ((ParameterizedTypeImpl) this.getClass().getGenericSuperclass()).getActualTypeArguments();
        if (actualTypeArguments.length != 2) {
            throw new ServiceException("对象获取异常");
        }
        Object o = xmlMapper.convertValue(entityStr, Class.forName(actualTypeArguments[0].getTypeName()));
        return (Req) o;
    }

问题阶段二

以上处理反序列化成对象,但有另一个问题,companys只获取到一个第二个节点,也就是NAME-2的值,NAME-1的值没有获取到。
在这里插入图片描述

问题阶段三

只获取到一个节点,有两个地址修改:

  1. 修改jackson-databind的版本,需要改为2.12.0版本以上,官方做了处理
    在这里插入图片描述

  2. 修改XmlDemoReqDto的定义,代码修改后如下:

@Data
@Builder
public class XmlDemoReqDto {
    @JacksonXmlProperty(localName = "USER_NAME")
    private String UserName;
    // 此处有变更
    @JacksonXmlProperty(localName = "COMPANYS")
    private Companys companys;
}

// 新增一个Companys的对象,里面包含company list
@Data
public class Companys {
    @JacksonXmlProperty(localName = "COMPANY")
    private List<Company> companies;
}

@Data
public class Company {
    @JacksonXmlProperty(localName = "COMPANYNAME")
    private String companyName;
}

按照上面的处理方式,可以正常解析出两个company了
在这里插入图片描述

问题阶段四

以上方法在传入的XML中company如果是两个节点,那是正常的,但如果只有一个节点,也就是下面那种,就会出现解析失败的情况,出现异常“java.lang.IllegalArgumentException: Cannot deserialize value of type java.util.ArrayList from Object value (token JsonToken.START_OBJECT)”。因为jackson处理时把companys解析成了一个普通对象,而非list。解决方法:在Companys对象中添加@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)。代码见下面

<TX> 
  <TX_HEADER> 
    <SYS_HDR_LEN/>  
    <SYS_PKG_VRSN>01</SYS_PKG_VRSN>
  </TX_HEADER> 
  <TX_EMB/>  
  <ENTITY> 
    <USER_NAME>xcc</USER_NAME> 
    <COMPANYS>
		<COMPANY>
			<COMPANYNAME>NAME-1</COMPANYNAME>
		</COMPANY>
     </COMPANYS>
  </ENTITY> 
</TX>
@Data
public class Companys {
    @JacksonXmlProperty(localName = "COMPANY")
    @JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
    private List<Company> companies;
}

处理以上四个阶段问题,消耗了我整整一天的时间,希望能给遇到相同问题的朋友一些解决思路。再次感谢ChatGPT在处理问题中给的一些思路,太有用了。
勉励:未来被人工智能淘汰的不是工程师,而是不会运用人工智能的工程师

参考

github jackson-databind issues 2733和2732
github jackson-dataformat-xml issues 339

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值