借鉴文章https://blog.csdn.net/pushme_pli/article/details/7829621
工作中遇到Java bean 和 XML之间转化的问题,采用XStream解决一些问题,注解式的开发很方便。
注解@XStreamAlias("Person") 是将"com.ruijie.spl.xhjy.util.bean.Person"起别名"Person",不然转换后的xml就是<com.ruijie.spl.xhjy.util.bean.Person></com.ruijie.spl.xhjy.util.bean.Person>而不是<Person></Person>
XStream的注解想要启用,必须告诉XStream对象使用注解,xStream.autodetectAnnotations(true);//通知XStream对象去识别annotation注解。Java bean 转化为xml时autodetectAnnotations可以使用,反序列化 xml 转化成Java bean 时,注解不起作用,想要启用注解,必须手动注册 xStream.processAnnotations(xmlClasses);//显式的注册需要使用annotation的类才行。建议将需要转化的Java bean 全放在一个包下,扫描包下面所有的实体对象,我就是这样做的
XStream在反序列化时,可能会报红色警告Security framework of XStream not initialized, XStream is probably vulnerable,想要去除警告,需要设置两个属性
XStream.setupDefaultSecurity(xStream);
xStream.allowTypes(xmlClasses);
下面是util里面xStream对象的设置以及需要的包
private static XStream xStream;
static{
Set<String> classNames = PackageUtil.getClassName("com.ruijie.spl.xhjy.util.bean", false);
@SuppressWarnings("rawtypes")
Class[] xmlClasses = getPackageClass(classNames);
xStream = new XStream(new DomDriver());
// xStream.autodetectAnnotations(true);//通知XStream对象去识别annotation注解
xStream.processAnnotations(xmlClasses);//显式的注册需要使用annotation的类才行
//去除Security framework of XStream not initialized, XStream is probably vulnerable.警告信息
XStream.setupDefaultSecurity(xStream);
xStream.allowTypes(xmlClasses);//将所有需要转化的实体类全部添加进去
}
<!-- 导入这个包可能报方法未定义的错误 比如autodetectAnnotations 无法设置true
<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2.2</version>
</dependency> -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.10</version>
</dependency>
<dependency>
<groupId>org.ogce</groupId>
<artifactId>xpp3</artifactId>
<version>1.1.6</version>
</dependency>
完整代码如下
package com.ruijie.spl.xhjy.util.bean;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("Person")
public class Person {
//姓名
private String name;
//性别
private String sex;
//年龄
private int age;
//地址
private List<Address> Address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Address> getAddress() {
return Address;
}
public void setAddress(List<Address> address) {
Address = address;
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age
+ ", Address=" + Address + "]";
}
}
package com.ruijie.spl.xhjy.util.bean;
import com.thoughtworks.xstream.annotations.XStreamAlias;
@XStreamAlias("Address")
public class Address {
//国
private String country;
//省
private String province;
//市
private String city;
//县
private String county;
//镇
private String town;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCounty() {
return county;
}
public void setCounty(String county) {
this.county = county;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
@Override
public String toString() {
return "Address [country=" + country + ", province=" + province
+ ", city=" + city + ", county=" + county + ", town=" + town
+ "]";
}
}
package com.ruijie.spl.xhjy.util;
import java.net.JarURLConnection;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* 获取包下的所有class
*/
public class PackageUtil {
public static void main(String[] args) throws Exception {
String packageName = "com.ruijie.spl.xhjy.util";
Set<String> classNames = getClassName(packageName, false);
if (classNames != null) {
for (String className : classNames) {
System.out.println(className);
}
}
}
/**
* 获取某包下所有类
* @param packageName 包名
* @param isRecursion 是否遍历子包
* @return 类的完整名称
*/
public static Set<String> getClassName(String packageName, boolean isRecursion) {
Set<String> classNames = null;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String packagePath = packageName.replace(".", "/");
URL url = loader.getResource(packagePath);
if (url != null) {
String protocol = url.getProtocol();
if (protocol.equals("file")) {
classNames = getClassNameFromDir(url.getPath(), packageName, isRecursion);
} else if (protocol.equals("jar")) {
JarFile jarFile = null;
try{
jarFile = ((JarURLConnection) url.openConnection()).getJarFile();
} catch(Exception e){
e.printStackTrace();
}
if(jarFile != null){
getClassNameFromJar(jarFile.entries(), packageName, isRecursion);
}
}
} else {
/*从所有的jar包中查找包名*/
classNames = getClassNameFromJars(((URLClassLoader)loader).getURLs(), packageName, isRecursion);
}
return classNames;
}
/**
* 从项目文件获取某包下所有类
* @param filePath 文件路径
* @param className 类名集合
* @param isRecursion 是否遍历子包
* @return 类的完整名称
*/
private static Set<String> getClassNameFromDir(String filePath, String packageName, boolean isRecursion) {
Set<String> className = new HashSet<String>();
File file = new File(filePath);
File[] files = file.listFiles();
for (File childFile : files) {
if (childFile.isDirectory()) {
if (isRecursion) {
className.addAll(getClassNameFromDir(childFile.getPath(), packageName+"."+childFile.getName(), isRecursion));
}
} else {
String fileName = childFile.getName();
if (fileName.endsWith(".class") && !fileName.contains("$")) {
className.add(packageName+ "." + fileName.replace(".class", ""));
}
}
}
return className;
}
/**
* @param jarEntries
* @param packageName
* @param isRecursion
* @return
*/
private static Set<String> getClassNameFromJar(Enumeration<JarEntry> jarEntries, String packageName, boolean isRecursion){
Set<String> classNames = new HashSet<String>();
while (jarEntries.hasMoreElements()) {
JarEntry jarEntry = jarEntries.nextElement();
if(!jarEntry.isDirectory()){
/*
* 这里是为了方便,先把"/" 转成 "." 再判断 ".class" 的做法可能会有bug
* (FIXME: 先把"/" 转成 "." 再判断 ".class" 的做法可能会有bug)
*/
String entryName = jarEntry.getName().replace("/", ".");
if (entryName.endsWith(".class") && !entryName.contains("$") && entryName.startsWith(packageName)) {
entryName = entryName.replace(".class", "");
if(isRecursion){
classNames.add(entryName);
} else if(!entryName.replace(packageName+".", "").contains(".")){
classNames.add(entryName);
}
}
}
}
return classNames;
}
/**
* 从所有jar中搜索该包,并获取该包下所有类
* @param urls URL集合
* @param packageName 包路径
* @param isRecursion 是否遍历子包
* @return 类的完整名称
*/
private static Set<String> getClassNameFromJars(URL[] urls, String packageName, boolean isRecursion) {
Set<String> classNames = new HashSet<String>();
for (int i = 0; i < urls.length; i++) {
String classPath = urls[i].getPath();
//不必搜索classes文件夹
if (classPath.endsWith("classes/")) {continue;}
JarFile jarFile = null;
try {
jarFile = new JarFile(classPath.substring(classPath.indexOf("/")));
} catch (IOException e) {
e.printStackTrace();
}
if (jarFile != null) {
classNames.addAll(getClassNameFromJar(jarFile.entries(), packageName, isRecursion));
}
}
return classNames;
}
}
package com.ruijie.spl.xhjy.util;
import java.util.Set;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
/**
* XStream工具类
* @author guo
* 2018年8月8日
*/
public class XStreamUtil {
private static XStream xStream;
static{
Set<String> classNames = PackageUtil.getClassName("com.ruijie.spl.xhjy.util.bean", false);
@SuppressWarnings("rawtypes")
Class[] xmlClasses = getPackageClass(classNames);
xStream = new XStream(new DomDriver());
// xStream.autodetectAnnotations(true);//通知XStream对象去识别annotation注解
xStream.processAnnotations(xmlClasses);//显式的注册需要使用annotation的类才行
//去除Security framework of XStream not initialized, XStream is probably vulnerable.警告信息
XStream.setupDefaultSecurity(xStream);
xStream.allowTypes(xmlClasses);
}
@SuppressWarnings("rawtypes")
private static Class[] getPackageClass(Set<String> classNames){
Class xmlClass ;
Class[] xmlClasses = new Class[classNames.size()];
int i = 0;
for (String className : classNames) {
try {
xmlClass = Class.forName(className).newInstance().getClass();
xmlClasses[i] = xmlClass;
i++;
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
e.printStackTrace();
}
}
return xmlClasses;
}
//xml转java对象
public static Object xmlToBean(String xml){
return xStream.fromXML(xml);
}
//java对象转xml
public static String beanToXml(Object obj){
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + xStream.toXML(obj);
}
}
package com.ruijie.spl.xhjy.util;
import java.util.ArrayList;
import java.util.List;
import com.ruijie.spl.xhjy.util.bean.Address;
import com.ruijie.spl.xhjy.util.bean.Person;
import com.thoughtworks.xstream.XStream;
public class TestXStream {
public static void main(String[] args) {
//测试java对象转xml,java对象中包含集合对象
Person person = new Person();
person.setName("admin管理员");
person.setSex("男");
person.setAge(25);
List<Address> adds = new ArrayList<Address>();
Address address1 = new Address();
address1.setCountry("中国");
address1.setProvince("安徽");
address1.setCity("宿州");
address1.setCounty("萧县");
Address address2 = new Address();
address2.setCountry("中国");
address2.setProvince("上海");
address2.setCity(null);
address2.setCounty("");
adds.add(address1);
adds.add(address2);
person.setAddress(adds);
XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
String xml = XStreamUtil.beanToXml(person);
System.out.println(xml);
//测试xml转java对象
Person person2 = (Person) XStreamUtil.xmlToBean(xml);
System.out.println(person2.toString());
}
}