使用反射技术,实现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

相关文章

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

Java枚举类实现Key-Value映射的多种实现方式

《Java枚举类实现Key-Value映射的多种实现方式》在Java开发中,枚举(Enum)是一种特殊的类,本文将详细介绍Java枚举类实现key-value映射的多种方式,有需要的小伙伴可以根据需要... 目录前言一、基础实现方式1.1 为枚举添加属性和构造方法二、http://www.cppcns.co

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当