package com.engine.salary.util.xml;

import cn.hutool.core.util.StrUtil;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
import com.thoughtworks.xstream.io.naming.NoNameCoder;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.security.AnyTypePermission;

import java.util.Objects;

public class XStreamUtil {
    //new NoNameCoder() 解决 _ 被序列化成 __ 的问题
    private static final NoNameCoder noNameCoder = new NoNameCoder();

    private static XStream xStream = new XStream(new DomDriver("UTF-8", noNameCoder));

    private static XStream getxStream(HierarchicalStreamDriver driver){
        if(Objects.isNull(driver)){
            return xStream;
        }
        return new XStream(driver);
    }

    public static <T> T unmarshal(String pkgName, Class<T> cla, String xmlStr, HierarchicalStreamDriver driver) {
        xStream = getxStream(driver);

        if (StrUtil.isEmpty(pkgName)) {
            //高版本为了解决安全漏洞，增加了白名单机制， 如果不设置这个权限可能会报错
            xStream.addPermission(AnyTypePermission.ANY);
        } else {
            //设置允许解析的包，如果不想设置可以用 addPermission(AnyTypePermission.ANY) 代替
            xStream.allowTypesByWildcard(new String[]{pkgName});
        }

        //支持注解，不然使用的XStream注解不会生效且不报错
        xStream.autodetectAnnotations(true);
        xStream.processAnnotations(cla);

        //忽略未知属性, 如果不添加这个，当Xml报文中出现实体中没有的属性时会报错 No such field
        xStream.ignoreUnknownElements();

        return (T) xStream.fromXML(xmlStr);
    }

    public static <T> T unmarshal(String pkgName, Class<T> cla, String xmlStr) {
        return unmarshal(pkgName, cla, xmlStr, null);
    }

    public static <T> T unmarshal(Class<T> cla, String xmlStr) {
        return unmarshal(null, cla, xmlStr, null);
    }

    public static String marshal(Object o, DomDriver driver) {
        xStream = getxStream(driver);

        //支持注解，不然使用的 @XStreamAlias() 注解不会生效而且不会报错
        xStream.autodetectAnnotations(true);

        //注册自定义时间转换器，使得XStream全局支持LocalDateTime， 或者不在这里注册，使用@XStreamConverter(LocalDateTimeConverter.class)注解在单一字段上
//        xStream.registerConverter(new LocalDateTimeConverter());
        return xStream.toXML(o);
    }

    public static String marshal(Object o){
        return marshal(o, null);
    }
}
