zoukankan      html  css  js  c++  java
  • Java关于xml序列化的自定义字段名称转换

    业务需要的情况下,偶尔需要使用到xml的序列化,如接入微信公众号时,推送的消息都是xml格式。有部分同学使用的是手动拼写xml,这个感觉不太爽,还是喜欢序列化工具,本文推荐使用XStream;

    话不多说,开始第一步引入包(使用的Maven)

            <dependency>
                <groupId>com.thoughtworks.xstream</groupId>
                <artifactId>xstream</artifactId>
                <version>1.4.7</version>
            </dependency>

    然后我们创建一个简单实体对象,在创建时,字段遵从驼峰式,如下

    public class TextMessage {
        private String toUserName;
        private String fromUserName;
        private Long createTime;
        private String msgType;
        private Long msgId;
        private String content;
        /*此处省略了getter && setter*/
    }

    xstream使用时,先创建对象如

     TextMessage msg = new TextMessage();
            msg.setContent("content");
            msg.setFromUserName("from");
            msg.setToUserName("to");
            msg.setCreateTime(1L);
            msg.setMsgType("text");
            msg.setMsgId(1L);
    
    XStream xstream=XStream();
    xstream.toXML(msg);

    得到的结果是

    <com.hanson.pojo.TextMessage>
      <toUserName>to</toUserName>
      <fromUserName>from</fromUserName>
      <createTime>1</createTime>
      <msgType>text</msgType>
      <msgId>1</msgId>
      <content>content</content>
    </com.hanson.pojo.TextMessage>

    可以看到有两点不符合微信的要求:

    1)根节点是class的全路径,期望是xml  ;

    2)元素节点名首字母需要大写(当前是声明的字段驼峰式)

    针对第一步,我们可以使用XStream的alias,如

     xstream.alias("xml", msg.getClass());
     xstream.toXML(msg);

    结果为

    <xml>
      <toUserName>to</toUserName>
      <fromUserName>from</fromUserName>
      <createTime>1</createTime>
      <msgType>text</msgType>
      <msgId>1</msgId>
      <content>content</content>
    </xml>

    下面需要修改元素节点的首字母,查找源码可以看到XStream的构造函数可传入HierarchicalStreamDriver,而实现这个接口可以传入NameCoder,如下接口描述

    public interface NameCoder {
        /**
         * Encode an object name for a node in the target format.
         * 
         * @param name the name of the object data
         * @return the node name in the target format
         * @since 1.4
         */
        String encodeNode(String name);
    
        /**
         * Encode a meta-data name for an attribute in the target format.
         * 
         * @param name the name of the meta-data
         * @return the attribute name in the target format
         * @since 1.4
         */
        String encodeAttribute(String name);
    
        /**
         * Decode a node name to an object name.
         * 
         * @param nodeName the name of the node
         * @return the name of the object
         * @since 1.4
         */
        String decodeNode(String nodeName);
    
        /**
         * Decode an attribute name to an object name.
         * 
         * @param attributeName the name of the attribute
         * @return the name of the meta-data
         * @since 1.4
         */
        String decodeAttribute(String attributeName);
    }

    从这个接口可以看出,可以实现此接口进行节点转换,完整代码如下

    public class FieldNameUtil {
        /**
         * 分割驼峰字段
         * @param name
         * @param separator
         * @return
         */
        private static String separateCamelCase(String name, String separator) {
            StringBuilder translation = new StringBuilder();
            for (int i = 0; i < name.length(); i++) {
                char character = name.charAt(i);
                if (Character.isUpperCase(character) && translation.length() != 0) {
                    translation.append(separator);
                }
                translation.append(character);
            }
            return translation.toString();
        }
        /**
         * 下划线转换为驼峰
         */
        public static String underscore2CamelCase(String name) {
            StringBuilder translation = new StringBuilder();
            for (int i = 0; i < name.length(); i++) {
                char character = name.charAt(i);
                if (character == '_')
                    continue;
                if (translation.length() != 0 && name.charAt(i - 1) == '_') {
                    translation.append(Character.toUpperCase(character));
                } else {
                    translation.append(character);
                }
            }
            return translation.toString();
        }
    
        /**
         * 驼峰转换为下划线
         * @param name
         * @return
         */
        public static String camelCase2Underscore(String name) {
            return separateCamelCase(name, "_").toLowerCase();
        }
    
        /**
         * 首字母大写
         * @param name
         * @return
         */
        public static String upperCaseFirstLetter(String name){
            StringBuilder fieldNameBuilder = new StringBuilder();
            int index = 0;
            char firstCharacter = name.charAt(index);
            while (index < name.length() - 1) {
                if (Character.isLetter(firstCharacter)) {
                    break;
                }
    
                fieldNameBuilder.append(firstCharacter);
                firstCharacter = name.charAt(++index);
            }
    
            if (index == name.length()) {
                return fieldNameBuilder.toString();
            }
    
            if (!Character.isUpperCase(firstCharacter)) {
                String modifiedTarget = modifyString(Character.toUpperCase(firstCharacter), name, ++index);
                return fieldNameBuilder.append(modifiedTarget).toString();
            } else {
                return name;
            }
        }
    
        /**
         * 首字母小写
         * @param name
         * @return
         */
        public static String lowerCaseFirstLetter(String name){
            StringBuilder fieldNameBuilder = new StringBuilder();
            int index = 0;
            char firstCharacter = name.charAt(index);
            while (index < name.length() - 1) {
                if (Character.isLetter(firstCharacter)) {
                    break;
                }
    
                fieldNameBuilder.append(firstCharacter);
                firstCharacter = name.charAt(++index);
            }
    
            if (index == name.length()) {
                return fieldNameBuilder.toString();
            }
    
            if (!Character.isLowerCase(firstCharacter)) {
                String modifiedTarget = modifyString(Character.toLowerCase(firstCharacter), name, ++index);
                return fieldNameBuilder.append(modifiedTarget).toString();
            } else {
                return name;
            }
        }
    
        /**
         * 修改字符串
         * @param firstCharacter
         * @param srcString
         * @param indexOfSubstring
         * @return
         */
        private static String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
            return (indexOfSubstring < srcString.length())
                    ? firstCharacter + srcString.substring(indexOfSubstring)
                    : String.valueOf(firstCharacter);
        }
    }
    import com.thoughtworks.xstream.io.naming.NameCoder;
    
    public class UpperCaseNameCoder implements NameCoder {
        public String encodeNode(String name) {
            return name.equalsIgnoreCase("xml")?"xml":FieldNameUtil.upperCaseFirstLetter(name);
        }
    
        public String encodeAttribute(String name) {
            return name.equalsIgnoreCase("xml")?"xml":FieldNameUtil.upperCaseFirstLetter(name);
        }
    
        public String decodeNode(String nodeName) {
            return FieldNameUtil.lowerCaseFirstLetter(nodeName);
        }
    
        public String decodeAttribute(String attributeName) {
            return FieldNameUtil.lowerCaseFirstLetter(attributeName);
        }
    }

    使用是,直接使用

     xstream=new XStream(new DomDriver("UTF-8", new UpperCaseNameCoder()));
     xstream.alias("xml", textMsg);
     xstream.toXML(obj);

    得到的结果

    <xml>
      <ToUserName>to</ToUserName>
      <FromUserName>from</FromUserName>
      <CreateTime>1</CreateTime>
      <MsgType>text</MsgType>
      <MsgId>1</MsgId>
      <Content>content</Content>
    </xml>

    总结:

    根据NameCoder接口实现,我们可以把驼峰式命名修改为匹配命名规则啦,比如下划线、中线、全大写下划线等,再也不用手拼字符串啦。

  • 相关阅读:
    使用tidylib解决不规则网页问题
    Python读取Json字典写入Excel表格的方法
    Python version 3.6 required, which was not found in the registry错误解决
    pip错误-failed to create process/fatal error in launcher
    Scrapy安装
    mongo数据库导入导出数据
    Windows命令
    Requests中文乱码解决方案
    mysql 1005 错误
    OC 内存管理-02 ARC 内存管理
  • 原文地址:https://www.cnblogs.com/HansonYao/p/8710468.html
Copyright © 2011-2022 走看看