XmlStream.java
package com.foxinmy.weixin4j.xml;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.Source;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.util.Consts;
import com.foxinmy.weixin4j.util.StringUtil;
/**
* XML 处理
*
* @className XmlStream
* @author jinyu(foxinmy@gmail.com)
* @date 2015年6月2日
* @since JDK 1.6
* @see
*/
public final class XmlStream {
private final static String ROOT_ELEMENT_XML = "xml";
private final static String XML_VERSION = "1.0";
private final static ConcurrentHashMap<Class<?>, JAXBContext> jaxbContexts = new ConcurrentHashMap<Class<?>, JAXBContext>();
private final static SAXParserFactory spf = SAXParserFactory.newInstance();
static {
try {
// This is the PRIMARY defense. If DTDs (doctypes) are disallowed,
// almost all XML entity attacks are prevented
// Xerces 2 only -
// http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
spf.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl",
true);
// If you can't completely disable DTDs, then at least do the
// following:
// Xerces 1 -
// http://xerces.apache.org/xerces-j/features.html#external-general-entities
// Xerces 2 -
// http://xerces.apache.org/xerces2-j/features.html#external-general-entities
// JDK7+ - http://xml.org/sax/features/external-general-entities
spf.setFeature(
"http://xml.org/sax/features/external-general-entities",
false);
// Xerces 1 -
// http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
// Xerces 2 -
// http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
// JDK7+ - http://xml.org/sax/features/external-parameter-entities
spf.setFeature(
"http://xml.org/sax/features/external-parameter-entities",
false);
// Disable external DTDs as well
spf.setFeature(
"http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
// and these as well, per Timothy Morgan's 2014 paper:
// "XML Schema, DTD, and Entity Attacks"
spf.setXIncludeAware(false);
} catch (Exception e) {
;
}
}
/**
* Xml2Bean
*
* @param content
* xml内容
* @param clazz
* bean类型
* @return
*/
@SuppressWarnings("unchecked")
public static <T> T fromXML(InputStream content, Class<T> clazz) {
JAXBContext jaxbContext = getJaxbContext(clazz);
try {
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
XMLReader reader = spf.newSAXParser().getXMLReader();
reader.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl",
true);
reader.setFeature(
"http://apache.org/xml/features/nonvalidating/load-external-dtd",
false); // This may not be strictly required as DTDs
// shouldn't be allowed at all, per previous line.
reader.setFeature(
"http://xml.org/sax/features/external-general-entities",
false);
reader.setFeature(
"http://xml.org/sax/features/external-parameter-entities",
false);
Source source = new SAXSource(reader, new InputSource(content));
XmlRootElement rootElement = clazz
.getAnnotation(XmlRootElement.class);
if (rootElement == null
|| rootElement.name().equals(
XmlRootElement.class.getMethod("name")
.getDefaultValue().toString())) {
JAXBElement<T> jaxbElement = unmarshaller.unmarshal(source,
clazz);
return jaxbElement.getValue();
} else {
return (T) unmarshaller.unmarshal(source);
}
} catch (Exception ex) {
throw new RuntimeException("Could not unmarshaller class [" + clazz
+ "]", ex);
} finally {
if (content != null) {
try {
content.close();
} catch (IOException e) {
;
}
}
}
}
/**
* Xml2Bean
*
* @param content
* xml内容
* @param clazz
* bean类型
* @return
*/
public static <T> T fromXML(String content, Class<T> clazz) {
return fromXML(
new ByteArrayInputStream(content.getBytes(Consts.UTF_8)), clazz);
}
/**
* map2xml
*
* @param map
* value无嵌套的map
* @return xml内容
*/
public static String map2xml(Map<String, String> map) {
StringWriter sw = new StringWriter();
try {
XMLStreamWriter xw = XMLOutputFactory.newInstance()
.createXMLStreamWriter(sw);
xw.writeStartDocument(Consts.UTF_8.name(), XML_VERSION);
xw.writeStartElement(ROOT_ELEMENT_XML);
for (Entry<String, String> entry : map.entrySet()) {
if (StringUtil.isBlank(entry.getValue())) {
continue;
}
xw.writeStartElement(entry.getKey());
xw.writeCData(entry.getValue());
xw.writeEndElement();
}
xw.writeEndDocument();
xw.flush();
xw.close();
} catch (XMLStreamException e) {
throw new IllegalArgumentException(e);
} finally {
try {
sw.close();
} catch (IOException e) {
;
}
}
return sw.getBuffer().toString();
}
/**
* map2xml
*
* @param json
* value无嵌套的json
* @return xml内容
*/
public static String map2xml(JSONObject json) {
StringWriter sw = new StringWriter();
try {
XMLStreamWriter xw = XMLOutputFactory.newInstance()
.createXMLStreamWriter(sw);
xw.writeStartDocument(Consts.UTF_8.name(), XML_VERSION);
xw.writeStartElement(ROOT_ELEMENT_XML);
for (Entry<String, Object> entry : json.entrySet()) {
if (StringUtil.isBlank(json.getString(entry.getKey()))) {
continue;
}
xw.writeStartElement(entry.getKey());
xw.writeCData(json.getString(entry.getKey()));
xw.writeEndElement();
}
xw.writeEndDocument();
xw.flush();
xw.close();
} catch (XMLStreamException e) {
throw new IllegalArgumentException(e);
} finally {
try {
sw.close();
} catch (IOException e) {
;
}
}
return sw.getBuffer().toString();
}
/**
* xml2map
*
* @param content
* 无嵌套节点的xml内容
* @return map对象
*/
public static Map<String, String> xml2map(String content) {
Map<String, String> map = new HashMap<String, String>();
StringReader sr = new StringReader(content);
try {
XMLStreamReader xr = XMLInputFactory.newInstance()
.createXMLStreamReader(sr);
while (true) {
int event = xr.next();
if (event == XMLStreamConstants.END_DOCUMENT) {
xr.close();
break;
} else if (event == XMLStreamConstants.START_ELEMENT) {
String name = xr.getLocalName();
while (true) {
event = xr.next();
if (event == XMLStreamConstants.START_ELEMENT) {
name = xr.getLocalName();
} else if (event == XMLStreamConstants.END_ELEMENT) {
break;
} else if (event == XMLStreamConstants.CHARACTERS) {
String value = xr.getText();
map.put(name, value);
}
}
}
}
} catch (XMLStreamException e) {
throw new IllegalArgumentException(e);
} finally {
sr.close();
}
return map;
}
/**
* Bean2Xml
*
* @param object
* bean对象
* @return xml内容
*/
public static String toXML(Object object) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
toXML(object, os);
return StringUtil.newStringUtf8(os.toByteArray());
}
/**
* Bean2Xml
*
* @param t
* bean对象
* @param os
* 输出流
*/
@SuppressWarnings("unchecked")
public static <T> void toXML(T t, OutputStream os) {
Class<T> clazz = (Class<T>) t.getClass();
JAXBContext jaxbContext = getJaxbContext(clazz);
try {
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING,
Consts.UTF_8.name());
XmlRootElement rootElement = clazz
.getAnnotation(XmlRootElement.class);
if (rootElement == null
|| rootElement.name().equals(
XmlRootElement.class.getMethod("name")
.getDefaultValue().toString())) {
marshaller.marshal(new JAXBElement<T>(new QName(
ROOT_ELEMENT_XML), clazz, t), os);
} else {
marshaller.marshal(t, os);
}
} catch (Exception ex) {
throw new RuntimeException("Could not marshal class [" + clazz
+ "] ", ex);
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
;
}
}
}
}
private static JAXBContext getJaxbContext(Class<?> clazz) {
JAXBContext jaxbContext = jaxbContexts.get(clazz);
if (jaxbContext == null) {
try {
jaxbContext = JAXBContext.newInstance(clazz);
jaxbContexts.putIfAbsent(clazz, jaxbContext);
} catch (JAXBException ex) {
throw new RuntimeException(
"Could not instantiate JAXBContext for class [" + clazz
+ "] ", ex);
}
}
return jaxbContext;
}
}