Home > other >  How to sort json by values in order to see real DIFF
How to sort json by values in order to see real DIFF

Time:09-22

I try to make a DIFF which does not look at order of my JSON values. I tried to sort my json before diffing it with import com.fasterxml.jackson.databind.ObjectMapper, but neither SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS or MapperFeature.SORT_PROPERTIES_ALPHABETICALLY sort it as I want. Somebody knows another way to sort my json by alphabetical values (NB_SUP_HET, NB_SUP_SOL, WEI_MAX) ?

import test.common.JsonDiff
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.MapperFeature
import javax.json.Json
import com.fasterxml.jackson.databind.ObjectMapper

String template = """    
    {"preparation_order_list" : [ {
      "net_weight_to_prepare" : 12.33,
      "additional_data_value_list" : [ {
        "additional_data_item_code" : "NB_SUP_HET",
        "additional_data_item_value" : "001821"
      }, {
        "additional_data_item_code" : "NB_SUP_SOL",
        "additional_data_item_value" : "002000"
      }, {
        "additional_data_item_code" : "WEI_MAX",
        "additional_data_item_value" : "000007358"
      } ]
    }]}
"""     
    
    String file_to_compare = """
    {"preparation_order_list" : [ {
      "net_weight_to_prepare" : 12.33,
      "additional_data_value_list" : [ {
        "additional_data_item_code" : "WEI_MAX",
        "additional_data_item_value" : "000007358"
      }, {
        "additional_data_item_code" : "NB_SUP_SOL",
        "additional_data_item_value" : "002000"
      }, {
        "additional_data_item_code" : "NB_SUP_HET",
        "additional_data_item_value" : "001821"
      } ]
    }]}
"""     
    
    
    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true);
    mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true)
    String prettyApiJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapper.readTree(file_to_compare));

    String prettyTemplateJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapper.readTree(template));
    println "------------------------------------------"
    println "prettyApiJson :\n$prettyApiJson"
    
    String diff_string = test.common.JsonDiff.GetJsonDiff(prettyApiJson,prettyTemplateJson)
    
    JsonStructure jsonStructInput = Json.createReader(new StringReader(prettyApiJson)).read()
    JsonStructure jsonStructTemplate = Json.createReader(new StringReader(prettyTemplateJson)).read()
    JsonPatch diff = Json.createDiff(jsonStructTemplate, jsonStructInput)
    println diff.toString()
    ```


CodePudding user response:

I tried another solution wich is to sort JsonSlurper() object by a recursive function. But it is hard to make it working as this is a complex object which seem composed of LinkedHashMap, ArrayList, LazyMap, ...

Somebody knows how to easily sort it ?

here is my code try...

def sortSubMap(def root, String keyToSort) {
    root.each {
        KeywordUtil.logInfo(") inspect:" it.inspect())
        KeywordUtil.logInfo("it "   it.getClass())
        KeywordUtil.logInfo("it.value "   it.value.getClass())
        if (it.key==keyToSort) {
            KeywordUtil.logInfo("*** it.key==keyToSort")
            //TODO :let's sort elements of this node "keyToSort" and replace in json_obj 
            
        } else if ( it.value instanceof groovy.json.internal.LazyMap) {
            KeywordUtil.logInfo("on recurse LazyMap")
            it.each { it1 -> sortSubMap(it1, keyToSort) }
            sortSubMap(it.value, keyToSort)
        } else if (it.value instanceof ArrayList) {
            KeywordUtil.logInfo("on recurse ArrayList")
            KeywordUtil.logInfo("it.value : "   it.value)
            sortSubMap(it.value, keyToSort)
        }
    }
}


def json_input = """
    {"items" : [ {
      "net_weight_to_prepare" : 12.33,
      "additional_data_value_list" : [ {
        "additional_data_item_code" : "WEI_MAX",
        "additional_data_item_value" : "000007358"
      }, {
        "additional_data_item_code" : "NB_SUP_SOL",
        "additional_data_item_value" : "002000"
      }, {
        "additional_data_item_code" : "NB_SUP_HET",
        "additional_data_item_value" : "001821"
      } ]
    }]}
""" 


def json_obj = new groovy.json.JsonSlurper().parseText(json_input)
println(json_obj.inspect())
sortSubMap(json_obj,"additional_data_value_list"); println(json_obj.inspect())

CodePudding user response:

for information, I finally succeeded to sort my "additional_data_value_list" by "additional_data_item_code" value alphabetically

Here is resulting recursive function with these strange closure functions :) :

import test.common.JsonDiff
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.MapperFeature
import javax.json.Json
import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.commons.lang3.builder.ToStringBuilder
import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import groovy.json.JsonBuilder

// inspired from https://stackoverflow.com/questions/39973481/recursively-removing-whitespace-from-json-field-names-in-groovy

def jsonString = """
    {"items" : [ {
      "net_weight_to_prepare" : 12.33,
      "additional_data_value_list" : [ {
        "additional_data_item_code" : "WEI_MAX",
        "additional_data_item_value" : "000007358"
      }, {
        "additional_data_item_code" : "NB_SUP_SOL",
        "additional_data_item_value" : "002000"
      }, {
        "additional_data_item_code" : "NB_SUP_HET",
        "additional_data_item_value" : "001821"
      } ]
    }]}
"""     


def json = """
{
    "leg bone" : false,
    "connected to  the" : {
        "arm bones " : [
            {
                " fizz" : "buzz",
                "well hello" : "there"
            }
        ]
    }
}
"""

def sortNodesInTree(def tree, String nodeName ) {
    println "tree1 : " tree
    //println "tree1.key : " tree.key
    switch (tree) {
        case Map:
            return tree.collectEntries { k, v -> 
                println "k v  : $k $v"
                if (k==nodeName) {[(k):v.sort { a,b -> a.additional_data_item_code <=> b.additional_data_item_code}]}
                else {
                [(k):sortNodesInTree(v,nodeName)]
                }
            }
        case Collection:
        println "tree2 : " tree
                return tree.collect { e -> sortNodesInTree(e,nodeName) }
        default :
            return tree
    }
}


def tree = new JsonSlurper().parseText(jsonString)
def fixedTree = sortNodesInTree(tree,"additional_data_value_list")
println new JsonBuilder(fixedTree).toString()

console :

println(JsonBuilder(fixedTree).toString())

{"items":[{"net_weight_to_prepare":12.33,"additional_data_value_list":[{"additional_data_item_code":"NB_SUP_HET","additional_data_item_value":"001821"},{"additional_data_item_code":"NB_SUP_SOL","additional_data_item_value":"002000"},{"additional_data_item_code":"WEI_MAX","additional_data_item_value":"000007358"}]}]}
  • Related