package com.artfess.base.util;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.Unmarshaller;

/**
 * jaxb工具类
 * 
 * @company 阿特菲斯信息技术有限公司
 * @author heyifan
 * @email heyf@jee-soft.cn
 * @date 2018年4月11日
 */
public class JAXBUtil {

	/**
	 * XML转换为POJO类型
	 * 
	 * @param xml
	 * @param clsToUnbound
	 * @return
	 * @throws JAXBException
	 * @throws UnsupportedEncodingException
	 */
	@SuppressWarnings("rawtypes")
	public static Object unmarshall(String xml, Class clsToUnbound) throws JAXBException, UnsupportedEncodingException {
		JAXBContext jc = JAXBContext.newInstance(clsToUnbound);

		return unmarshall(jc, xml);
	}

	/**
	 * XML转换为POJO类型
	 * 
	 * @param jc
	 * @param xml
	 * @return
	 * @throws JAXBException
	 * @throws UnsupportedEncodingException
	 */
	private static Object unmarshall(JAXBContext jc, String xml) throws JAXBException, UnsupportedEncodingException {
		Unmarshaller u = jc.createUnmarshaller();
		InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
		return u.unmarshal(is);
	}

	/**
	 * 从流中反序列化对象。
	 * 
	 * @param cls
	 *            需要反序列化的对象类型。
	 * @param xmlIs
	 *            流对象
	 * @return 经过反序列化的对象实例。
	 * @throws JAXBException
	 */
	public static Object unmarshall(InputStream xmlIs, Class<?> cls) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(cls);
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		Object obj = unmarshaller.unmarshal(xmlIs);
		return obj;
	}

	@SuppressWarnings("unchecked")
	public Object unmarshall(String xml, Class<? extends Object>... classes) throws JAXBException, IOException {
		InputStream is = new ByteArrayInputStream(xml.getBytes());
		JAXBContext jc = JAXBContext.newInstance(classes);
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		unmarshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
		Object obj = unmarshaller.unmarshal(is);
		return obj;
	}

	/**
	 * POJO类型转换为XML
	 * 
	 * @param serObj
	 * @param clsToBound
	 * @return
	 * @throws JAXBException
	 */
	@SuppressWarnings("rawtypes")
	public static String marshall(Object serObj, Class clsToBound) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(clsToBound);
		return marshall(jc, serObj, true, false);
	}
	/**
	 * POJO类型转换为XML
	 * @param serObj
	 * @param fragment 是否隐藏报文头
	 * @return
	 * @throws JAXBException
	 */
	public static String marshall(Object serObj, boolean formatOutput, boolean fragment) throws JAXBException {
		JAXBContext jc = JAXBContext.newInstance(serObj.getClass());
		return marshall(jc, serObj, formatOutput, fragment);
	}
	public static String marshall(Object serObj, boolean formatOutput) throws JAXBException {
		return marshall(serObj, formatOutput, false);
	}

	/**
	 * POJO类型转换为XML
	 * 
	 * @param jc
	 * @param serObj
	 * @return
	 * @throws JAXBException
	 * @throws PropertyException
	 */
	private static String marshall(JAXBContext jc, Object serObj, boolean formatOutput, boolean fragment) throws JAXBException, PropertyException {
		StringWriter out = new StringWriter();
		Marshaller m = jc.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, formatOutput);
		m.setProperty(Marshaller.JAXB_FRAGMENT, fragment);
		m.setProperty(Marshaller.JAXB_ENCODING, "utf-8");
		m.marshal(serObj, out);
		String tmp = out.toString();
		return tmp;
	}

	/**
	 * 将类序列化到流中。
	 * 
	 * @param contextPath
	 *            需要序列化到类名
	 * @param obj
	 *            需要序列化的实例对象
	 * @param stream
	 *            需要序列化到的流对象。
	 * @throws JAXBException
	 */
	public static void marshall(String contextPath, Object obj, OutputStream stream) throws JAXBException {

		JAXBContext jc = JAXBContext.newInstance(contextPath);
		Marshaller m = jc.createMarshaller();
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
		m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
		m.marshal(obj, stream);
	}

	public static void main(String[] args) {
		System.out.println(System.getProperty("file.encoding"));

	}

}
