Search code examples
jsonarraylistgroovyjsonbuilderjsonslurper

How to get key from ArrayList nested in JSON using Groovy and change its value


I need to be able to find the key quote.orderAttributes[0].attributeDetail.name and set its value to null or any other value I want. I only need to do this for the first element in any list so selecting [0] is fine. I want to be able to use a path such as 'quote.orderAttributes.attributeDetail.name'. But given the amount of time I've spent so far, please advise of any better approaches.

Here is the Json:

{
  "source": "source",
  "orderId": null,
  "Version": null,
  "quote": {
    "globalTransactionId": "k2o4-6969-1fie-poef",
    "quoteStatus": "Not Uploaded",
    "events": {
      "eventDescription": "event description",
      "eventTypeName": "Event Type"
    },
    "someReport": {
      "acceptResultsFlag": "Y",
      "orderDate": "2017-06-14",
      "orderStatus": "string"
    },
    "anotherReport": {
      "id": 627311,
      "orderDate": "2017-06-14"
    },
    "attributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name1",
          "value": "value1"
        },
        "attributeName": "attribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name2",
          "value": "value2"
        },
        "attributeName": "attribute2"
      }
    ],
    "orderAttributes": [
      {
        "appliedFlag": "Y",
        "attributeDetail": {
          "name": "name3",
          "value": "value3"
        },
        "attributeName": "orderAttribute1"
      },
      {
        "appliedFlag": "N",
        "attributeDetail": {
          "name": "name4",
          "value": "value4"
        },
        "attributeName": "orderAttribute2"
      }
    ]
  }
}

I know the following works but requires that I know which object(s) is an ArrayList and specify its [0] indexed item:

def input = new File("src/test/resources/ShortExample.json")
def json = new JsonSlurper().parse(input)
def option1 = json['quote']["attributes"][0]["attributeDetail"]["name"]
println option1

//or this 
//where csvData.fullPath = quote.orderAttributes.attributeDetail.name

def (tkn1, tkn2, tkn3, tkn4) = csvData.fullPath.tokenize('.')
def option2 = json["$tkn1"]["$tkn2"][0]["$tkn3"]["$tkn4"]
println option2

I would like to be able to:

def input = new File("src/test/resources/ShortExample.json")
def json = new JsonSlurper().parse(input)
def changeValueTo = null
def (tkn1, tkn2, tkn3, tkn4) = csvData.fullPath.tokenize('.')
json["$tkn1"]["$tkn2"]["$tkn3"]["$tkn4"] = changeValueTo

I've tried to implement many of the examples on here using recursion, methods creating MapsOrCollections that identify what the object is and then search it for key or value, even trampoline examples.

If you could point me to a good article explaining serialization and deserialization it would be much appreciated too.

Thank you in advance.


Solution

  • as variant:

    import groovy.json.*;
    
    def json = '''{
      "source": "source",
      "orderId": null,
      "Version": null,
      "quote": {
        "globalTransactionId": "k2o4-6969-1fie-poef",
        "quoteStatus": "Not Uploaded",
        "attributes": [
          {
            "appliedFlag": "Y",
            "attributeDetail": {
              "name": "name1",
              "value": "value1"
            },
            "attributeName": "attribute1"
          },
          {
            "appliedFlag": "N",
            "attributeDetail": {
              "name": "name2",
              "value": "value2"
            },
            "attributeName": "attribute2"
          }
        ]}
      }'''
    
    json = new JsonSlurper().parseText(json)
    
    def jsonx(Object json, String expr){
        return Eval.me('ROOT',json, expr)
    }
    
    println jsonx(json, 'ROOT.quote.attributes[0].attributeDetail.name')
    jsonx(json, 'ROOT.quote.attributes[0].attributeDetail.name = null')
    println jsonx(json, 'ROOT.quote.attributes[0].attributeDetail.name')