天天看點

XStream JAVA bean 和XML互相轉化

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