Установка значения делегата с помощью Groovy JsonBuilder

(Это дополнительный вопрос к вопросу, заданному здесь)

Я использую JsonBuilder Groovy для динамического генерирования следующего JSON:

{
    "type": {
        "__type": "urn",
        "value": "myCustomValue1"
    },
    "urn": {
        "__type": "urn",
        "value": "myCustomValue2"
    },
    "date": {
        "epoch": 1265662800000,
        "str": "2010-02-08T21:00:00Z"
    },
    "metadata": [{
        "ratings": [{
            "rating": "NR",
            "scheme": "eirin",
            "_type": {
                "__type": "urn",
                "value": "myCustomValue3"
            }
        }],
        "creators": [Jim, Bob, Joe]
    }]
}

Используя этот код:

def addUrn(parent, type, urnVal) {
    parent."$type" {
        __type "urn"
        "value" urnVal
    }
}

String getEpisode(String myCustomVal1, String myCustomVal2, String myCustomVal3) {    
    def builder = new groovy.json.JsonBuilder()
    builder {
        addUrn(delegate, "type", myCustomVal1)
        addUrn(delegate, "urn", "some:urn:$myCustomVal2")
        "date" {
            epoch 1265662800000
            str "2010-02-08T21:00:00Z"
        }
       "metadata" ({
                ratings ({
                        rating "G"
                        scheme "eirin"
                        addUrn(delegate, "_type", "$myCustomVal3")
                })
                creators "Jim", "Bob", "Joe"                    
        })
    }

    return root.toString();
}

Код выбрасывает StackruError из-за третьего звонка addUrn (под вложенным ratings элемент. Если я прокомментирую эту строку, она отлично работает (кроме того факта, что мне не хватает необходимого куска информации).

  1. Почему это происходит?
  2. Как установить делегата для непосредственного родителя, например ratings?

Я пытался использовать метакласс безрезультатно.

1 ответ

Решение

Это довольно некрасиво (LOL), но даст вам ожидаемый результат:

def addUrn(parent, type, urnVal) {
    parent."$type" {
        __type "urn"
        "value" urnVal
    }
}

String getEpisode(String myCustomVal1, String myCustomVal2, String myCustomVal3) {
    def builder = new groovy.json.JsonBuilder()
    def root = builder {
        addUrn(delegate, "type", myCustomVal1)
        addUrn(delegate, "urn", "some:urn:$myCustomVal2")
        "date" {
            epoch 1265662800000
            str "2010-02-08T21:00:00Z"
        }
        "metadata" ([{([
                "ratings" ([{
                        rating "G"
                        scheme "eirin"
                        this.addUrn(delegate, "_type", "$myCustomVal3")
                }]),
                creators ("Jim", "Bob", "Joe")
        ])}])
    }

    println builder.toPrettyString()
}

Заметка:-

  • В предыдущем вопросе я ошибся, сказав, что делегат должен ссылаться на непосредственного родителя. На самом деле это относится к непосредственному родителю. Вместо этого мы должны обратиться к сценарию (который имеетaddUrn метод) при вызове метода, следовательно, использование this при звонке addUrn внутри рейтинги. В качестве альтернативы вы можете отправить "рейтинги" по методу, аналогичному addUrn,
  • Использование и последовательность скобок, цепочки и квадратной скобки важны для того, что вы видите после "метаданных". Давать понять, что здесь будет громоздко. Но единственное, на что нужно обратить внимание, - это придерживаться основ использования вызовов методов, объявления списков и использования замыканий. Попробуйте сделать отступ для каждой фигурной скобки в каждой строке, чтобы получить магию.:)
  • Причиной ошибки StackOverFlow было то, что метод getEpisode не смог добраться до метода addUrn который принадлежит сценарию.

Протестируйте его прямо в Groovy Web Console

Другие вопросы по тегам