使用反射技术,实现XML与对象相互转换(自己封装的超类,相互学习)

2024-05-08 17:58

本文主要是介绍使用反射技术,实现XML与对象相互转换(自己封装的超类,相互学习),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

       对于网上的各种将XML同对象相互转换的方法比较多,但是如果对方给你提供的XML并非标准的XML格式,恐怕就只能自己封装方法了。作者在调用某票务公司提供的接口时,由于其返回XML流存在不标准的结构,因此自己写了个超类,继承于这个超类的所有对象可以调用toXml()、toObject(String xml)实现互转。

      通过反射技术实现,如有不足之处,欢迎批评指正,非常感谢!

注意:

      1、转换对象的属包含常见类型,如超类未涉及,请自行添加。

  List/Integer(int)/String/Double(double)/Float(float)/Date/Long(long)/Short(short)/Byte(byte)/该类的子类

      2、代码中的一些“未知”类

      (1)ServiceException:自定义的运行时异常,请自行添加

      (2)DateUtil:时间格式化工具,请自行封装

      (3)StringUtil:字符串工具,使用到的方法:判断Object是否为空

      3、需引入的包

<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
<dependency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/dom4j/dom4j -->
<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>1.6.1</version>
</dependency>

      4、代码中存在与作者接受的业务相关内容,请自行处理(去掉红框中的判断逻辑)

上代码

      1、接口

/*** 实现此接口的对象可以和XML相互转换* @author WolfShadow* @date 2018年11月19日*/
public interface Convertible {String toXml();<T> T toObject(String xml);
}

      2、超类

import java.io.StringReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;//TODO 请自行添加这几个类或使用其他方式取代
import com.***.ServiceException;
import com.***.DateUtil;
import com.***.StringUtil;
import com.***.Convertible;/*** 可与XML相互转换的超类* 此类的所有子类可实现与XML互相转换* 终极优化:子类不再需要重写该2方法,转换对象的属包含常见类型,如超类未涉及,请自行添加* List/Integer(int)/String/Double(double)/Float(float)/Date/Long(long)/Short(short)/Byte(byte)/该类的子类* * @author WolfShadow* @date 2018年11月15日*/
public class ConvertibleObject implements Convertible{@Overridepublic String toString() {return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);}/*** 通用将当前对象(this)转换成XML串,不包含<?xml version="1.0" encoding="UTF-8"?>* @return* @auther WolfShadow* @date 2018年11月30日*/@Overridepublic String toXml() {StringBuffer sBuffer = new StringBuffer();Class<? extends ConvertibleObject> class1 = this.getClass();/*** 按照**提供的XML文档规范,类名首字母小写作为一个节点*/String name = class1.getSimpleName();name = name.replaceFirst(".", name.substring(0, 1).toLowerCase());sBuffer.append("<").append(name).append(">");Field[] fields = class1.getDeclaredFields();String fieldName = null;Object value = null;try {for(Field field : fields){//通过反射机制遍历类的所有属性及值fieldName = field.getName();Class<?> type = field.getType();field.setAccessible(true);if(type.equals(List.class)){//1.List属性// 判断List的成员是否是Convertible实现类ParameterizedType genericType = (ParameterizedType)field.getGenericType();Type[] arguments = genericType.getActualTypeArguments();Class<?> class2 = Class.forName(arguments[0].toString().replaceFirst("class ", ""));Class<?> superclass = class2.getSuperclass();if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类List<ConvertibleObject> list = (List<ConvertibleObject>)field.get(this);if (list == null) {continue;}sBuffer.append("<").append(fieldName).append(">");for(ConvertibleObject object : list){if (object != null) {sBuffer.append(object.toXml());}}}else {sBuffer.append(this.getFieldValue(field,class2));}sBuffer.append("</").append(fieldName).append(">");}else {//2.ConvertibleObject 子类Class<?> superclass = type.getSuperclass();if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类ConvertibleObject object = (ConvertibleObject)field.get(this);if (object != null) {sBuffer.append(object.toXml());}}else{//3.其他简单类型value = this.getFieldValue(field,type);//统一获取属性值的方法if (value == null) {continue;}sBuffer.append("<").append(fieldName).append(">");sBuffer.append(value);sBuffer.append("</").append(fieldName).append(">");}}}} catch (Exception e) {throw new ServiceException("class: "+this+" 转换成XML字符串时出错!");}sBuffer.append("</").append(name).append(">");return sBuffer.toString();}/*** 将XML转换成当前对象(this)* @param xml* @return* @auther WolfShadow* @date 2018年11月30日*/@Overridepublic <T> T toObject(String xml) {if (!this.verifyXML(xml)) {return null;}Class<? extends ConvertibleObject> class1 = this.getClass();/*** 按照**提供的XML文档规范,类名首字母小写作为一个节点*/String name = class1.getSimpleName();name = name.replaceFirst(".", name.substring(0, 1).toLowerCase());Field[] fields = class1.getDeclaredFields();String fieldName = null;String value = null;SAXReader reader = new SAXReader();Document document = null;try {document = reader.read(new StringReader(xml));//读取XML流为DocumentElement root = document.getRootElement();Element fieldE = null;for(Field field : fields){//通过反射机制遍历类的所有属性fieldName = field.getName();Class<?> type = field.getType();field.setAccessible(true);if(type.equals(List.class)){//1.List属性// 本可通用的方法,但因为**返回的XML存在不统一的情况,因此对products属性对应的XML需要特殊处理List<Element> elements = null;if ("products".equals(fieldName)) {elements = root.elements("product");}else{Element element = root.element(fieldName);elements = element.elements();}if (elements == null || elements.size() < 1) {continue;}// 判断List的成员是否是Convertible实现类ParameterizedType genericType = (ParameterizedType)field.getGenericType();Type[] arguments = genericType.getActualTypeArguments();Class<?> class2 = Class.forName(arguments[0].toString().replaceFirst("class ", ""));Class<?> superclass = class2.getSuperclass();List<Object> list = new ArrayList<>();if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类Object instance = class2.newInstance();Method method = class2.getMethod("toObject", String.class);Method method2 = class2.getMethod("isEmpty");Object invoke = null;for(Element e : elements){instance = method.invoke(instance, e.asXML());invoke = method2.invoke(instance);if (invoke != null && Boolean.FALSE.equals(invoke)) {list.add(instance);}}}else{for(Element e : elements){list.add(e.getStringValue());}}field.set(this, list);}else {fieldE = root.element(fieldName);if (fieldE == null) {continue;}//2.ConvertibleObject子类Class<?> superclass = type.getSuperclass();if (superclass != null && superclass.equals(ConvertibleObject.class)) {//子类Object instance = type.newInstance();Method method = type.getMethod("toObject", String.class);Method method2 = type.getMethod("isEmpty");Object invoke = null;instance = method.invoke(instance, fieldE.asXML());invoke = method2.invoke(instance);if (invoke != null && Boolean.FALSE.equals(invoke)) {field.set(this, instance);}}else{//其他普通类型value = fieldE.getStringValue();if (StringUtil.isNullOrEmpty(value)) {continue;}this.setField(field, value, type);}}}return (T) this;//强制转换成其子类} catch (ServiceException e) {throw e;} catch (Exception e) {throw new ServiceException("class: "+this+" 转换XML字符串为对象时出错!");}}/*** 常用类型属性值的设置* @param field* @param valueObj* @auther WolfShadow* @date 2018年11月22日*/public void setField(Field field, String value, Class<?> classType){//field.setAccessible(true);try {if (classType.equals(Integer.class) || classType.equals(int.class)) {field.set(this, Integer.parseInt(value));}else if (classType.equals(Long.class) || classType.equals(long.class)) {field.set(this, Long.parseLong(value));}else if (classType.equals(Short.class) || classType.equals(short.class)) {field.set(this, Short.parseShort(value));}else if (classType.equals(Float.class) || classType.equals(float.class)) {field.set(this, Float.parseFloat(value));}else if (classType.equals(Double.class) || classType.equals(double.class)) {field.set(this, Double.parseDouble(value));}else if (classType.equals(Byte.class) || classType.equals(byte.class)) {field.set(this, Byte.parseByte(value));}else if (classType.equals(String.class)) {field.set(this, value.toString());}else if (classType.equals(Date.class)) {int length = value.length();if (length == 10) {//YYYY-MM-ddvalue += " 00:00:00";}else if (length == 16) {//YYYY-MM-dd HH:mmvalue += ":00";}else {}field.set(this, DateUtil.str2Date(value));}else if (classType.equals(Boolean.class) || classType.equals(boolean.class)) {field.set(this, Boolean.parseBoolean(value));}else if (classType.equals(Object.class)) {field.set(this, value);}else {//如果未考虑到的属性类型,这里抛出异常throw new ServiceException("基础置换类不支持此种属性的转换");}} catch (ServiceException e) {throw e;} catch (Exception e) {throw new ServiceException("class: "+this+" 转换XML字符串为对象时出错!");}}/*** 常用类型属性值的获取* @param field* @param valueObj* @auther WolfShadow* @date 2018年11月22日*/public String getFieldValue(Field field, Class<?> type){//field.setAccessible(true);try {Object valueObj = field.get(this);if (StringUtil.isNullOrEmpty(valueObj)) {return null;}if (type.equals(Integer.class) || type.equals(int.class)) {}else if (type.equals(Long.class) || type.equals(long.class)) {}else if (type.equals(Short.class) || type.equals(short.class)) {}else if (type.equals(Float.class) || type.equals(float.class)) {}else if (type.equals(Double.class) || type.equals(double.class)) {}else if (type.equals(Byte.class) || type.equals(byte.class)) {}else if (type.equals(String.class)) {}else if (type.equals(Date.class)) {//只处理时间格式return DateUtil.date2Str((Date)valueObj);}else if (type.equals(Boolean.class) || type.equals(boolean.class)) {}else if (type.equals(Object.class)) {}else {//如果未考虑到的属性类型,这里抛出异常//throw new ServiceException("基础置换类不支持此种属性的转换");}return valueObj.toString();} catch (ServiceException e) {throw e;} catch (Exception e) {throw new ServiceException("class: "+this+" 转换XML字符串为对象时出错!");}}/*** 默认情况下不需要做XML判断,但是在解析原始(标准)XML时需要重写该方法判断解析的XML是否合法* @param xml* @return* @auther WolfShadow* @date 2018年11月23日*/public boolean verifyXML(String xml){//return xml.startsWith(xmlheader) || xml.startsWith(xmlheader_low);return true;}/*** 对象为空* @return* @throws IllegalArgumentException* @throws IllegalAccessException* @auther WolfShadow* @date 2018年11月23日*/public boolean isEmpty() throws IllegalArgumentException, IllegalAccessException{Class<? extends ConvertibleObject> class1 = this.getClass();Field[] fields = class1.getDeclaredFields();Object object = null;for(Field field : fields){try {field.setAccessible(true);object = field.get(this);} catch (Exception e) {object = null;}if (!StringUtil.isNullOrEmpty(object)) {return false;}}return true;}
}

 

 

      

这篇关于使用反射技术,实现XML与对象相互转换(自己封装的超类,相互学习)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/971028

相关文章

SpringBoot集成redisson实现延时队列教程

《SpringBoot集成redisson实现延时队列教程》文章介绍了使用Redisson实现延迟队列的完整步骤,包括依赖导入、Redis配置、工具类封装、业务枚举定义、执行器实现、Bean创建、消费... 目录1、先给项目导入Redisson依赖2、配置redis3、创建 RedissonConfig 配

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

Spring Security简介、使用与最佳实践

《SpringSecurity简介、使用与最佳实践》SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,本文给大家介绍SpringSec... 目录一、如何理解 Spring Security?—— 核心思想二、如何在 Java 项目中使用?——

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

springboot中使用okhttp3的小结

《springboot中使用okhttp3的小结》OkHttp3是一个JavaHTTP客户端,可以处理各种请求类型,比如GET、POST、PUT等,并且支持高效的HTTP连接池、请求和响应缓存、以及异... 在 Spring Boot 项目中使用 OkHttp3 进行 HTTP 请求是一个高效且流行的方式。

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函