Использование метакласса Groovy для реализации специальных методов

Я пытаюсь изменить метакласс для JSONObject в Groovy, чтобы он вел себя как можно больше, как обычная карта Groovy. Когда я реализую методы в метаклассе, некоторые из них просты, например JSONObject.metaClass.size в приведенном ниже примере. JSONObject имеет метод length (), и я просто подключаю его к новому методу size (), но некоторые методы имеют особое значение. Например, чтобы присвоение индекса работало, мне пришлось переопределить свойствоMissing, а не putAt. Похоже, что многие операции сбора, такие как each, collect, findAll и т. Д., Похожи.

Мой первый вопрос: какие специальные методы мне нужно переопределить в этом случае, чтобы каждый () работал? Мой второй вопрос: как мне самому найти ответ? Есть ли где-нибудь ссылка на методы, которые получают от СС особые меры? Я попытался посмотреть исходный код groovy-core, но там много всего, и я не знаю, с чего начать.

JSONObject.metaClass.propertyMissing = { String name, newValue -> delegate.put(name, newValue) }
JSONObject.metaClass.size = { -> delegate.length() }
JSONObject.metaClass.each = { cl -> delegate.keys().collectEntries{ [(it): delegate[it] ]}.each(cl) }

def json = new JSONObject()
json['a'] = 999
json.b    = 2.2
json['c'] = 'the letter C'
println json['a']            // Prints 999
println json['b']            // Prints 2.2
println json.c               // 'the letter C'
println json.size()         // Prints 3

//No signature of method: ... $__spock_feature_0_0_closure4.doCall() is applicable 
json.each{ k,v -> println "$k = $v"}

person John Stanford    schedule 15.06.2017    source источник
comment
какой JSONObject? не могли бы вы дать полное название класса?   -  person daggett    schedule 17.06.2017
comment
org.json.JSONArray и org.json.JSONObject из 'org.json: json: 20160810'   -  person John Stanford    schedule 18.06.2017


Ответы (1)


@Grab(group='org.json', module='json', version='20160810')

import org.json.JSONArray
import org.json.JSONObject

JSONObject.metaClass.each={Closure c-> 
    delegate.keys().each{ k-> c(k, delegate.get(k) ) }  
}

JSONObject.metaClass.setProperty={String k, Object v-> 
    delegate.put(k,v) 
}

JSONObject.metaClass.getProperty={String k-> 
    delegate.get(k) 
}

JSONObject.metaClass.size = { -> delegate.length() }

def json = new JSONObject()
json['a'] = 999
json.b    = 2.2
json['c'] = 'the letter C'
println json['a']            // Prints 999
println json['b']            // Prints 2.2
println json.c               // 'the letter C'
println json.size()         // Prints 3

//No signature of method: ... $__spock_feature_0_0_closure4.doCall() is applicable 
json.each{ k,v -> println "$k = $v"}

вывод:

999
2.2
the letter C
3
a = 999
b = 2.2
c = the letter C
person daggett    schedule 19.06.2017
comment
Это работает :) Спасибо! Думаю, я подходил к этому более или менее правильно, но я неправильно написал каждое закрытие. - person John Stanford; 20.06.2017