1

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.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131
SleepyD
  • 39
  • 1
  • 2
  • 9
  • You can't avoid explicit `attributes[0]` because simply saying `attributes` is also a valid reference but to a whole list of objects. When you explicitly say `attributes[0]` you point to a specific element of that list. – Szymon Stepniak Oct 04 '17 at 06:44

2 Answers2

1

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')
daggett
  • 26,404
  • 3
  • 40
  • 56
  • Perfect!! I hope many come to this post and vote up your answer. There are so many other questions on this site similar to this question but have much more complicated solutions. Eval is new to me. Great answer!!! – SleepyD Oct 03 '17 at 22:17
0

You can access and modify any nested field of JSON object directly, e.g.

json.quote.attributes[0].attributeDetail.name = null

This is possible, because new JsonSlurper().parse(input) returns a groovy.json.internal.LazyMap object. Groovy allows you to access and modify any Map entries using dot notation, e.g.

Map<String, Map<String, Integer>> map = [
    lorem: [ipsum: 1, dolor: 2, sit: 3]
]

println map.lorem.ipsum // Prints '1'
map.lorem.ipsum = 10
println map.lorem.ipsum // Prints '10'

You can apply same approach to your example, e.g.

import groovy.json.JsonSlurper

String input = '''{
  "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"
      }
    ]
  }
}'''

def json = new JsonSlurper().parse(input.bytes)

assert json.quote.attributes[0].attributeDetail.name == 'name1'

json.quote.attributes[0].attributeDetail.name = null

assert json.quote.attributes[0].attributeDetail.name == null

I hope it helps.

Szymon Stepniak
  • 40,216
  • 10
  • 104
  • 131