构造
package com.shunnengnet.infra.util;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class XstreamUtils {
/**
* 将bean转换为xml
*
* @param obj 转换的bean
* @return bean转换为xml
*/
public static String toXml(Object obj) {
XStream xStream = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("_-", "_")));
//xstream使用注解转换
xStream.processAnnotations(obj.getClass());
xStream.allowTypeHierarchy(obj.getClass());
xStream.autodetectAnnotations(true);
String xml = xStream.toXML(obj);
return xml.replace("&", "&").replace(""", "\"").replace("<", "<")
.replace(">", ">").replace("'", "'");
}
/**
* 将xml转换为bean
*
* @param <T> 泛型
* @param xml 要转换为bean的xml
* @param cls bean对应的Class
* @return xml转换为bean
*/
public static <T> T toObject(String xml, Class<T> cls) {
XStream xstream = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("_-", "_")));
//xstream使用注解转换
xstream.processAnnotations(cls);
xstream.allowTypeHierarchy(cls);
xstream.autodetectAnnotations(true);
return cls.cast(xstream.fromXML(xml));
}
/**
* xml转成映射好的实体
* @param xml xml字符
* @param cl 类
* @param classes 多层嵌套的类的数组
* @param <T> 类的类型
* @return <T> T 返回需要的类型
*/
public static <T> T toObject(String xml, Class<T> cl, Class<?>[] classes) {
XStream xstream = new XStream(new DomDriver("UTF_8", new XmlFriendlyNameCoder("-_", "_")));
xstream.processAnnotations(cl);
if (null == classes || classes.length == 0) {
xstream.allowTypeHierarchy(cl);
} else {
xstream.allowTypes(classes);
}
xstream.autodetectAnnotations(true);
return cl.cast(xstream.fromXML(xml));
}
/**
* 对象转成映射好的xml字符
* @param obj 对象
* @return 最终xml
*/
public static String toXmlNoReplace(Object obj) {
XStream xStream = new XStream(new DomDriver("UTF_8", new XmlFriendlyNameCoder("-_", "_")));
xStream.processAnnotations(obj.getClass());
xStream.allowTypeHierarchy(obj.getClass());
xStream.autodetectAnnotations(true);
return xStream.toXML(obj);
}
}
自定义转换器
@XStreamConverter(value = CdataConverter.class)
public class CdataConverter implements Converter {
@Override
public boolean canConvert(Class type) {
return String.class.isAssignableFrom(type);
}
@Override
public void marshal(Object o, HierarchicalStreamWriter writer, MarshallingContext marshallingContext) {
String cData = (String) o;
writer.setValue("<![CDATA["+cData+"]]"+">");
}
/**
* Convert textual data back into an object.
*
* @param reader The stream to read the text from.
* @param context
* @return The resulting object.
*/
@Override
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
return reader.getValue();
}
}
//自带的转换器,将text之外的属性定义为节点的属性,text为该节点的值
@XStreamConverter(value = ToAttributedValueConverter.class,strings = {“text”})
使用实例
Address
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@XStreamAlias("_Address")
public class Address implements Serializable {
private static final long serialVersionUID = -2204135694698262519L;
@XStreamAlias("_Country")
private String country;
@XStreamAlias("_Province")
private String province;
@XStreamAlias("_City")
@XStreamConverter(value = CdataConverter.class)
private String city;
}
Person
@ToString
@XStreamAlias("Person")
@AllArgsConstructor
@NoArgsConstructor
public class Person implements Serializable {
private static final long serialVersionUID = 8703644148766584973L;
@XStreamAsAttribute
private String type;
/**
* XStreamOmitField 忽略此属性
*/
@XStreamOmitField
private String id;
/**
* XmlElment实体主要是为了方便在该标签上添加属性
*/
@XStreamAlias("_Name")
private XmlElement name;
/**
* 定义属性别名
*/
@XStreamAlias("_Sex")
private String sex;
@XStreamAlias("_Age")
private int age;
@XStreamAlias("_Addresses")
// @XStreamImplicit // 去除根标签 addresses
private List<Address> addresses;
}
XmlElement 属性及节点值
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
//自带的转换器,将text之外的属性定义为节点的属性,text为该节点的值
@XStreamConverter(value = ToAttributedValueConverter.class,strings = {
"text"})
public class XmlElement implements Serializable {
private static final long serialVersionUID = 6490005123023660218L;
private String attribute;
private String text;
}
执行样例
@Test
void contextLoads() {
XStream xStream = new XStream(new DomDriver("UTF_8",
new XmlFriendlyNameCoder("-_", "_")));
//自动注解扫描,否则注解不生效
xStream.autodetectAnnotations(true);
List<Address> list = new ArrayList<>();
list.add(new Address("China", "ShanDong", "JiNan"));
list.add(new Address("China", "ShanDong", "LiaoCheng"));
Person person = new Person("中国人","1", new XmlElement("中文名", "汤姆"), "Male", 18,list);
log.info("实体信息:{}",person);
String s = xStream.toXML(person);
String sTo = XStreamUtils.toXml(person);
log.info("转换的xml:{}",s);
log.info("转换的xml:{}",sTo);
log.error("转换的xml-转义后:{}", StringEscapeUtils.unescapeXml(sTo));
}
@Test
public void test01(){
String xml =
"<?xml version=\"1.0\" encoding=\"GBK\"?>\n" +
"<Person type=\"中国人\">\n" +
" <_Name attribute=\"中文名\">汤姆</_Name>\n" +
" <_Sex>Male</_Sex>\n" +
" <_Age>18</_Age>\n" +
" <_Addresses>\n" +
" <_Address>\n" +
" <_Country>China</_Country>\n" +
" <_Province>ShanDong</_Province>\n" +
" <_City>JiNan</_City>\n" +
" </_Address>\n" +
" <_Address>\n" +
" <_Country>China</_Country>\n" +
" <_Province>ShanDong</_Province>\n" +
" <_City>LiaoCheng</_City>\n" +
" </_Address>\n" +
" </_Addresses>\n" +
"</Person>";
/*"<?xml version=\"1.0\" encoding=\"GBK\"?>\n" +
"<Person type=\"中国人\">\n" +
" <_Name attribute=\"中文名\">汤姆</_Name>\n" +
" <_Sex>Male</_Sex>\n" +
" <_Age>18</_Age>\n" +
" <_Addresses>\n" +
" <_Address>\n" +
" <_Country>China</_Country>\n" +
" <_Province>ShanDong</_Province>\n" +
" <_City>JiNan</_City>\n" +
" </_Address>\n" +
" <_Address>\n" +
" <_Country>China</_Country>\n" +
" <_Province>ShanDong</_Province>\n" +
" <_City>LiaoCheng</_City>\n" +
" </_Address>\n" +
" </_Addresses>\n" +
"</Person>";*/
XStream xStream = new XStream(new DomDriver("UTF_8",
new XmlFriendlyNameCoder("-_", "_")));
xStream.processAnnotations(Person.class);
xStream.autodetectAnnotations(true);
//com.thoughtworks.xstream.security.ForbiddenClassException 报错解决
//1.
Class<?>[] classes = new Class[]{
Person.class,Address.class};
// xStream.allowTypes(classes);
//2.
// xStream.allowTypeHierarchy(Person.class);
// xStream.allowTypeHierarchy(Address.class);
Person person = XStreamUtils.toObject(xml,Person.class,classes);
//如果没有嵌套 执行 XStreamUtils.toObject(xml,Person.class,null);
// Person person = (Person)xStream.fromXML(xml);
log.info("翻转实体:{}",person);
}
}