2

我正在抓取外部资源,主要是 JSON。我new JsonSlurper().parse(body)用来解析它们,并使用诸如def name = json.user[0].name. 这些是外部的,可以在没有通知的情况下更改,所以我希望能够检测到这一点并以某种方式记录它。

在阅读了一些关于 MOP 的信息后,我认为如果缺少属性,我可以更改地图和列表的适当方法以记录。我只想json递归地执行对象及其属性。问题是,我不知道该怎么做。

或者,有没有更好的方法来完成这一切?

[编辑] 例如,如果我得到这个 JSON:

def json = '''{
  "owners": [
    {
      "firstName": "John",
      "lastName": "Smith"
    },
    {
      "firstName": "Jane",
      "lastName": "Smith"
    }
  ]
}'''

def data = new groovy.json.JsonSlurper().parse(json.bytes)
assert data.owners[0].firstName == 'John'

但是,如果他们将“所有者”更改为“所有者信息”,则上述访问将引发 NPE。我想要的是拦截访问并做一些事情(比如将它记录在一个特殊的日志中,或者其他什么)。我也可以决定抛出一个更专业的异常。

我不想捕获 NullPointerException,因为它可能是由我的代码中的一些错误而不是更改的数据格式引起的。此外,如果他们将“firstName”更改为“givenName”,但保留“owners”名称,我只会得到一个null值,而不是NPE. 理想情况下,我也想检测这种情况。

如果可能的话,我也不想放置很多 if 或 evlis 运算符。

我实际上设法拦截了地图:

data.getMetaClass().getProperty = {name -> println ">>> $name"; delegate.get(name)}
assert data.owners // this prints ">>> owners"

我仍然无法找到如何为列表执行此操作:

def owners = data.owners
owners.getMetaClass().getAt(o -> println "]]] $o"; delegate.getAt(o)}
assert owners[0] // this doesn't print anything
4

2 回答 2

3

尝试这个

owners.getMetaClass().getAt = { Integer o -> println "]]] $o"; delegate.get(o)}

我只是猜测它因为多个 getAt() 方法而丢失了,所以你必须定义类型。我还委托给 ArrayList 的 Java get() 方法,因为 getAt() 会导致递归调用。

如果您想更好地控制所有方法调用,您可以随时执行此操作

owners.getMetaClass().invokeMethod = { String methodName, Object[] args ->
    if (methodName == "getAt") {
        println "]]] $args"
    }
    return ArrayList.getMetaClass().getMetaMethod(methodName, args).invoke(delegate, args)
}
于 2015-12-18T09:24:48.273 回答
1

简短的回答是你不能用给定的例子做到这一点。原因是owners对象是 a java.util.ArrayList,并且您正在调用get(int index)它的方法。该metaClass对象是 Groovy 特有的,如果您有一个 Java 对象对 Java 方法进行方法调用,它将不知道metaClass. 这是一个有点相关的问题

好消息是有选项,尽管我不确定它是否适用于您的用例。您可以为此列表创建一个 Groovy 包装器对象,以便您可以捕获方法调用。

例如,您可以从此更改您的代码

def owners = data.owners

对此

def owners = new GroovyList(data.owners)

然后创建这个新类

class GroovyList {
    private List list

    public GroovyList(List list) {
        this.list = list
    }

    public Object getAt(int index) {
        println "]]] $index"
        list.getAt(index)
    }
}

现在当你打电话

owners[0]

你会得到输出

]]] 0
[firstName:John, lastName:Smith]
于 2015-12-17T21:24:56.517 回答