如何拦截map getProperty和list getAt?

时间:2015-12-15 16:07:51

标签: json groovy web-scraping mop

我正在抓取外部资源,主要是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'

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

我不想捕获NullPointerException,因为它可能是由我的代码中的某些错误而不是更改的数据格式引起的。此外,如果他们将“firstName”更改为“givenName”,但保留了“所有者”的名称,我只会获得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

2 个答案:

答案 0 :(得分: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)
}

答案 1 :(得分:1)

简短的回答是,您不能使用给定的示例执行此操作。原因是owners对象是java.util.ArrayList,您在其上调用get(int index)方法。 metaClass对象特定于Groovy,如果您有一个Java对象对Java方法进行方法调用,它将不知道metaClassHere's a somewhat related question

好消息是和选项,虽然我不确定它是否适用于您的用例。您可以为此列表创建一个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]