• 基于jackson的kotlin json字符串对比器


    package comparator
    
    import com.fasterxml.jackson.core.JsonParser
    import com.fasterxml.jackson.databind.DeserializationFeature
    import com.fasterxml.jackson.databind.JsonNode
    import com.fasterxml.jackson.databind.ObjectMapper
    import com.fasterxml.jackson.databind.node.JsonNodeType
    import com.fasterxml.jackson.databind.node.NumericNode
    import java.util.*
    import kotlin.Comparator
    
    
    enum class CompareType {
        /*
         * both compare name and value, but if name missing found, compare stop, and print the result, or it will compare all values are the same until find difference.
         */
        COMPARE_NAME,
        /*
         * if name missing found, compare stop and print the result.
         */
        COMPARE_NAME_VALUE
    }
    
    internal class NumberComparator : Comparator<JsonNode> {
        override fun compare(o1: JsonNode, o2: JsonNode): Int {
            if (o1 == o2) {
                return 0
            }
            if (o1 is NumericNode && o2 is NumericNode) {
                val d1 = o1.asDouble()
                val d2 = o2.asDouble()
                if (d1.compareTo(d2) == 0) {
                    return 0
                }
            }
            return 1
        }
    }
    
    class Comparator {
        constructor(){
            debug=false;
            TYPE_COMPARE = CompareType.COMPARE_NAME_VALUE
            IGNORED_FILED_LIST = java.util.ArrayList<String>();
        }
        constructor(debugI: Boolean?, compareType:String?, ignoreFieldList: String?){
            if(debugI != null) {debug=debugI;}
    
            var type = CompareType.COMPARE_NAME_VALUE
            if (compareType != null && compareType.trim { it <= ' ' } !== "") {
                if (CompareType.COMPARE_NAME_VALUE.toString().equals(compareType, ignoreCase = true)) {
                    type = CompareType.COMPARE_NAME_VALUE
                } else if (CompareType.COMPARE_NAME.toString().equals(compareType, ignoreCase = true)) {
                    type = CompareType.COMPARE_NAME
                }
            }
            TYPE_COMPARE = type
    
    
            var ignoredFields: ArrayList<String> = java.util.ArrayList<String>();
            if (ignoreFieldList == null || ignoreFieldList.trim { it <= ' ' }.length == 0) {
                if(debug){
                    println("no valid ignored field list")
                }
    
            } else {
                var fs:kotlin.collections.List<String> = ignoreFieldList.split(",");
                for(f:String in fs){
                    var fTrimed:String = f.trim();
                    if(fTrimed.length > 0){
                        ignoredFields.add(fTrimed)
                    }
                }
            }
            IGNORED_FILED_LIST = ignoredFields;
    
    
            if(debug){
                println("selected compare type:" + TYPE_COMPARE)
            }
            if(debug){
                println("selected ignored field list:" + IGNORED_FILED_LIST)
            }
        }
    
        fun compare(path: String, o1: JsonNode?, o2: JsonNode?, res: ArrayList<Diff?>) {
            // basic input check
            if (o1 == null) {
                if (o2 != null) {
                    res.add(Diff(pathGetter(path, ""), MISS_NAME_TIP_WORD, ""))
                }
                return
            }
            if (o2 == null) {
                res.add(Diff(pathGetter(path, ""), "", MISS_NAME_TIP_WORD))
                return
            }
            val typeO1 = o1.nodeType
            val typeO2 = o2.nodeType
            if (typeO1 != typeO2) {
                val diff = Diff(pathGetter(path, ""), typeO1.name, typeO2.name)
                addAndfilterDiffRes(res, diff)
                return
            }
            val type = o1.nodeType
            if (type == JsonNodeType.ARRAY) {
                val nodeArrLeft: MutableList<JsonNode> = ArrayList()
                val iteratorLeft = o1.elements()
                while (iteratorLeft.hasNext()) {
                    nodeArrLeft.add(iteratorLeft.next())
                }
                val nodeArrRight: MutableList<JsonNode> = ArrayList()
                val iteratorRight = o2.elements()
                while (iteratorRight.hasNext()) {
                    nodeArrRight.add(iteratorRight.next())
                }
                if (nodeArrLeft.size == nodeArrRight.size) {
                    for (i in 0 until o1.size()) {
                        compare(pathGetter(path, o1.toString()+"["+i+"]"), nodeArrLeft[i], nodeArrRight[i], res)
                    }
                } else if (nodeArrLeft.size > nodeArrRight.size) {
                    val lefti = nodeArrLeft[nodeArrRight.size]
                    val diff = Diff(pathGetter(path, "["+nodeArrRight.size+"]"), lefti.toString(), MISS_NAME_TIP_WORD)
                    addAndfilterDiffRes(res, diff)
                } else {
                    val righti = nodeArrRight[nodeArrLeft.size]
                    val diff = Diff(pathGetter(path, "["+nodeArrLeft.size+"]"), MISS_NAME_TIP_WORD, righti.toString())
                    addAndfilterDiffRes(res, diff)
                }
            } else if (type == JsonNodeType.OBJECT) {
                val o1NameSet = getNamesSet(o1.fieldNames())
                val o2NameSet = getNamesSet(o2.fieldNames())
                val sameList: MutableList<String> = ArrayList()
                // compare node name size
                // check key is the same
                for (key in o1NameSet) {
                    if (!o2NameSet.contains(key)) {
                        val diff = Diff(pathGetter(path, key), o1[key].toString(), MISS_NAME_TIP_WORD)
                        addAndfilterDiffRes(res, diff)
                    } else {
                        sameList.add(key)
                    }
                }
                for (key in o2NameSet) {
                    if (!o1NameSet.contains(key)) {
                        val diff = Diff(pathGetter(path, key), MISS_NAME_TIP_WORD, o2[key].toString())
                        addAndfilterDiffRes(res, diff)
                    }
                }
    
                // compare node value
                for (key in sameList) {
                    val nodeleft = o1[key]
                    val noderight = o2[key]
                    val typeObjLeft = nodeleft.nodeType
                    val typeObjRight = noderight.nodeType
                    if (typeObjLeft != typeObjRight) {
                        val diff = Diff(pathGetter(path, key), typeObjLeft.name, typeObjRight.name)
                        addAndfilterDiffRes(res, diff)
                    } else {
                        if (typeObjLeft == JsonNodeType.ARRAY) {
                            val nodeArrLeft: MutableList<JsonNode> = ArrayList()
                            val iteratorLeft = nodeleft.elements()
                            while (iteratorLeft.hasNext()) {
                                nodeArrLeft.add(iteratorLeft.next())
                            }
                            val nodeArrRight: MutableList<JsonNode> = ArrayList()
                            val iteratorRight = noderight.elements()
                            while (iteratorRight.hasNext()) {
                                nodeArrRight.add(iteratorRight.next())
                            }
                            if (nodeArrLeft.size == nodeArrRight.size) {
                                for (i in nodeArrLeft.indices) {
                                    compare(pathGetter(path, key+"["+i+"]"), nodeArrLeft[i], nodeArrRight[i], res)
                                }
                            } else if (nodeArrLeft.size > nodeArrRight.size) {
                                val diff = Diff(
                                    pathGetter(path, key+"["+nodeArrRight.size+"]"),
                                    nodeArrLeft[nodeArrRight.size].toString(),
                                    MISS_NAME_TIP_WORD
                                )
                                addAndfilterDiffRes(res, diff)
                            } else {
                                val diff = Diff(
                                    pathGetter(path, key + "["+nodeArrLeft.size+"]"),
                                    MISS_NAME_TIP_WORD,
                                    nodeArrRight[nodeArrLeft.size].toString()
                                )
                                addAndfilterDiffRes(res, diff)
                            }
                        } else if (typeObjLeft == JsonNodeType.OBJECT) {
                            compare(pathGetter(path, key), nodeleft, noderight, res)
                        } else {
                            if (TYPE_COMPARE == CompareType.COMPARE_NAME) {
                                // just compare names
                                continue
                            }
                            if (!nodeleft.equals(NumberComparator(), noderight)) {
                                val diff = Diff(pathGetter(path, key), nodeleft.toString(), noderight.toString())
                                addAndfilterDiffRes(res, diff)
                            }
                        }
                    }
                }
            } else {
                if (TYPE_COMPARE == CompareType.COMPARE_NAME) {
                    // just compare names
                    return
                }
                if (!o1.equals(NumberComparator(), o2)) {
                    val diff = Diff(pathGetter(path, ""), o1.toString(), o2.toString())
                    addAndfilterDiffRes(res, diff)
                }
            }
            return
        }
    
        fun getNamesSet(it: Iterator<String>): TreeSet<String> {
            val res = TreeSet<String>()
            while (it.hasNext()) {
                val name = it.next()
                res.add(name)
            }
            return res
        }
    
        fun pathGetter(parent: String, key: String?): String {
            val path = StringBuilder()
            if (parent == "") {
                path.append(key)
            } else if (key == null || "" == key.trim { it <= ' ' }) {
                path.append(parent)
            } else {
                path.append(parent).append(".").append(key)
            }
            return path.toString()
        }
    
        fun addAndfilterDiffRes(res: MutableList<Diff?>, diff: Diff) {
            if (!IGNORED_FILED_LIST.contains(diff.node)) {
                res.add(diff)
            }
        }
    
        /**
         *
         * @param compareType <br></br>
         * support two compare type set at agrs[0]: COMPARE_NAME_VALUE, COMPARE_NAME <br></br>
         *
         *
         * COMPARE_NAME_VALUE:both compare name and value, but if name missing found, compare stop, and print the result<br></br>
         * COMPARE_NAME:if name missing found, compare stop and print the result
         *
         */
        fun getCompareResult(left: String?, right: String?): ArrayList<Diff?> {
    
            var leftNode: JsonNode? = null
            try {
                leftNode = mapper.readTree(left)
            } catch (e: Exception) {
                if(debug){
                    println("left parse failed:" + e.message)
                }
            }
            var rightNode: JsonNode? = null
            try {
                rightNode = mapper.readTree(right)
            } catch (e: Exception) {
                if(debug){
                    println("right parse failed:" + e.message)
                }
            }
            return getCompareResultWithJson(leftNode, rightNode)
        }
    
        fun getCompareResultWithJson(
            left: JsonNode?,
            right: JsonNode?
        ): ArrayList<Diff?> {
            val res: ArrayList<Diff?> = ArrayList<Diff?>()
            try {
                compare("\$root", left, right, res)
            } catch (e: Exception) {
                if(debug){
                    println("compare failed:" + e.message)
                }
            }
            return res
        }
    
        companion object {
            // fields to ignore when compare
            lateinit var IGNORED_FILED_LIST:ArrayList<String>;
            var TYPE_COMPARE = CompareType.COMPARE_NAME_VALUE
            var MISS_NAME_TIP_WORD = "not exist"
            public val mapper = ObjectMapper()
            public var debug:Boolean = false;
    
            init {
                mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true)
                mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
            }
        }
    }
    

      

  • 相关阅读:
    程序人生,编程思想
    CentOS Linux Jenkins安装、部署、更新
    Git常用命令
    U盘安装Mac OS X要点
    Shell执行*.sql
    WebStorm远程调试Node.js
    svn常用命令
    敏捷开发相关编辑思想(SOA、DDD、REST、CQRS)
    VisualVM远程监控Java
    centos搭建git服务
  • 原文地址:https://www.cnblogs.com/bigjor/p/16107749.html
Copyright © 2020-2023  润新知