借鑒文章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());
}
}