-
Notifications
You must be signed in to change notification settings - Fork 0
AOP
Philip Ford edited this page Aug 26, 2017
·
7 revisions
I used the example below in a unit test. I had a custom FileDecorator class that wrapped a File object. I wanted to avoid writes to files during the unit test. The code below overrides the behavior of all instances of the original class, and intercepts calls to the write(), getText(), and renameTo() methods, redirecting them to a datastore (a map) instead of to the File object and the file system.
class Proxy extends DelegatingMetaClass {
def data = [:]
Proxy(final Class cls) {
super(cls)
initialize()
}
public Object invokeMethod(Object obj, String method, Object[] args) {
String cls = obj.class.simpleName
println "before: $cls.$method, args:$args -->"
def val = null
// Creating a map of instance data, with the absolute path of
// the wrapped File as the key.
if (!data.get(obj.cmp.getAbsolutePath())){
data.put(obj.cmp.getAbsolutePath(), [
text:obj.text
])
}
// Advising only the write, getText, and renameTo methods
if (method == 'write'){
data.put(obj.cmp.getAbsolutePath(), [text: args[0]])
return obj
} else if (method == 'getText'){
def text = data[obj.cmp.getAbsolutePath()].text
println "[getText]\n$text"
return text
} else if (method == 'renameTo'){
def text = data[obj.cmp.getAbsolutePath()].text
obj.cmp = new File(args[0])
data.put(obj.cmp.getAbsolutePath(), [ text: text ])
return data[obj.cmp.getAbsolutePath()]
} else if (method == 'readLines'){
return data[obj.cmp.getAbsolutePath()].text.split('\n')
} else {
try {
val = super.invokeMethod(obj, method, args)
} catch(Exception e) {
println "after: $cls.$method, has thrown:$e <--"
throw e
}
}
println "after: $cls.$method, return value:$val <--"
return val;
}
def static setClass(Class cls) {
cls.metaClass = new Proxy(cls)
}
}