简介
本篇文章主要解决了上篇文章中遗留的对象嵌套问题,要想全面解析无限极的对象嵌套需要使用递归去解决
上文链接:
使用CXF调用WSDL(一)
上文回顾
上文使用了单方法“ call() ”解决了List和基本类型(含String)以及对象的解析,但遗留了对象嵌套问题,本文将把 “ call() ” 方法中关于对象解析的部分拆分出独立的方法 “ analysisParam() ”,然后使用递归解决对象的嵌套问题
正文
/**
* 调用远程过程
*/
public Object call(DTGMM1020GERP paramEntity) {
Object result = null;
log.info("[PO创建时]入参:{}",JSON.toJSONString(paramEntity,true));
Map map = JSONObject.parseObject(JSON.toJSONString(paramEntity, SerializerFeature.WriteDateUseDateFormat), Map.class);
Map<String,Object> wsdl = getWSDLContent();
Client client = (Client) wsdl.get("client");
List<MessagePartInfo> partInfos = (List<MessagePartInfo>) wsdl.get("messagePartInfo");
QName qName = (QName) wsdl.get("qname");
String clazzName = partInfos.get(0).getTypeClass().getName();
try {
Object requestParamObject = Thread.currentThread().getContextClassLoader().loadClass(clazzName).newInstance();
requestParamObject = analysisParam(requestParamObject,map);
log.info("请求参数:{}",JSON.toJSON(requestParamObject));
result = client.invoke(qName, requestParamObject);
log.info("响应结果:{}",JSON.toJSONString(result,true));
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
解说:方法 “ call() ” 接收一个 “ DTGMM1020GERP ” 对象作为入参并返回一个Object对象,该方法主要业务就是将入参对象转换成map对象,而后读取WSDL文件内容,并传入给 “ analysisParam() ” 方法解析,其中requestParamObject是读出的WSDL文件的节点,map是待写入节点的值
private static Object analysisParam(Object req, Map map) throws InstantiationException, IllegalAccessException {
Field[] fields = req.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
boolean b = field.getGenericType() instanceof ParameterizedType;
//如果是泛型并且是List类型
if(b && field.getType() == List.class){
List<?> cParam = (List<?>) map.get(field.getName());
log.info("子对象参数:{}",cParam);
if(CollectionUtils.isEmpty(cParam)){
continue;
}
Type type = ((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0];
Class<?> aClass = (Class<?>) type;
Object cObj = aClass.newInstance();
log.info("子对象:{}",cObj);
Field[] cFields = cObj.getClass().getDeclaredFields();
for (Field cField : cFields) {
cField.setAccessible(true);
List<?> target = cParam.stream().map(o -> {
Map ccParam = JSONObject.parseObject(JSON.toJSONString(o),Map.class);
Object strParam = ccParam.get(cField.getName());
//如果子对象类型是基本类型或String类型那就直接赋值,负责就递归
if(cField.getType().isPrimitive() || cField.getType() == String.class){
try {
if(null != strParam){
cField.set(cObj,strParam);
}
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}else{
try {
Object obj = cField.getType().newInstance();
Map objMap = JSONObject.parseObject(JSON.toJSONString(strParam),Map.class);
if(!CollectionUtils.isEmpty(objMap)){
analysisParam(obj,objMap);
cField.set(cObj,obj);
}
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return strParam;
}).collect(Collectors.toList());
/*Object targetResp = target.get(0);
cField.set(cObj,targetResp);*/
}
List<Object> cObjs = new ArrayList<>();
cObjs.add(cObj);
//给父对象赋值
field.set(req,cObjs);
}else if(field.getType().isPrimitive() || field.getType() == String.class){
//如果是基本类型或String类型
field.set(req,map.get(field.getName()));
}else{
//按对象处理
Object o = field.getType().newInstance();
Map childrenObjMap = (Map) map.get(field.getName());
if(!CollectionUtils.isEmpty(childrenObjMap)){
writeFieldValue(o,childrenObjMap);
field.set(req,o);
}
}
}
return req;
}
步骤解析:
一、使用反射获取待解析节点的字段
二、进行第一层 for 循环解析节点,先判断了字段的类型是否为泛型且为List类型,如果不是泛型且不是List类型,再判断是否为基本类型或是String类型,如果也不是,那就当成普通对象处理
三、如果第一层 for 循环中的类型为泛型且为List类型时,则进行第二层 for 循环处理,第二层循环同样判断子对象字段值是否为基本类型或String类型,如果是则直接赋值,如果不是,则说明是一个对象,至于是个什么对象(List?基本类型?String?POJO?),无需理会,直接进行递归解析即可
注意:map的key需和待解析的节点字段名保持一致,因为map.get()是通过field.getName()取值的
本文中引用到的其他方法请从上一篇文章中获取
使用CXF调用WSDL(一)
完成
文末
这是我mock加数据的方法,入参对象可以使用该方法快速生成mock数据(本文中的DTGMM1020GERP )
public static <T> T getEntityData(T t) {
Field[] field = t.getClass().getDeclaredFields();
for (Field f : field) {
f.setAccessible(true);
try {
Random random = new Random();
int num = random.nextInt(10);
f.set(t,""+num);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
return t;
}
用法
只需要定义好对象的嵌套层级即可
List<DTGMM1020GERP> list = new ArrayList<>();
DTGMM1020GERP entity = new DTGMM1020GERP();
entity = getEntityData(entity);
list.add(entity);