我有一个抽象的基础POGO:
abstract class AuthorizingResource {
void authorize(String credential) {
if(!credentialIsValid(credential)) {
throw new AuthorizationException(credential)
}
}
boolean credentialIsValid(String credential) {
// Do stuff to determine yea or nay
}
}
许多具体的子类如下:
class FizzResource extends AuthorizingResource {
List<Fizz> getAllFizzes(String credential) {
authorize(credential)
List<Fizz> fizzes
// Do stuff
fizzes
}
Fizz getFizzById(String credential, Long id) {
authorize(credential)
Fizz fizz
// Do stuff
fizz
}
void considerTheLillies(Buzz buzz) {
// Do stuff
}
void upsertFizz(String credential, Fizz fizz) {
authorize(credential)
// Do stuff
}
}
正如您所看到的,有几件事情正在发生:
FizzResource
方法,我需要在方法顶部手动调用authorize(...)
considerTheLillies
)不需要进行修改我想知道我是否可以通过使用闭包调用authorize(...)
来模仿AOP(所以我不必无意中添加它)可以使用某种模式来选择“换行”的方法封闭内部。在FizzResource
的特定情况下,这将是包含“*Fizz*
”的任何方法,但该模式应该(理想情况下)是任何有效的正则表达式。 无法改变的一件事是,任何接受credential
arg的方法都无法修改其签名。
基本上,像Spring AOP或Google Guice的方法拦截器,但使用原生的Groovy闭包。
有什么想法吗?
答案 0 :(得分:2)
您可以将GroovyInterceptable
与fizz
一起使用。请注意,名称中的任何abstract class AuthorizingResource implements GroovyInterceptable {
def invoked = []
def validator = [credentialIsValid : { true }]
void authorize(String credential) {
if ( !validator.credentialIsValid(credential) ) {
throw new RuntimeException(credential)
}
}
def invokeMethod(String method, args) {
if (method.toLowerCase().contains('fizz')) {
metaClass.getMetaMethod('authorize', String).invoke(this, args[0])
invoked.add( 'authorized ' + method )
}
return metaClass
.getMetaMethod(method, args*.getClass() as Class[])
.invoke(this, args)
}
}
class Fizz { String name }
class FizzResource extends AuthorizingResource {
List<Fizz> getAllFizzes(String credential) { ['all fizzes'] }
Fizz getFizzById(String credential, Long id) { new Fizz(name: 'john doe') }
def considerTheLillies() { 42 }
}
res = new FizzResource()
assert res.getAllFizzes('cred') == ['all fizzes']
assert res.considerTheLillies() == 42
assert res.getFizzById('cred', 10l).name == 'john doe'
assert res.invoked == ['authorized getAllFizzes', 'authorized getFizzById']
都将匹配:
Option Private Module
答案 1 :(得分:0)
我无法停止考虑基于闭包的解决方案。我想出了一些Javascript样式代码,使用了闭包和贴图。它没有继承:
class AuthorizingResource {
void authorize(String credential) {
if(!credentialIsValid(credential)) {
throw new RuntimeException(credential)
}
}
boolean credentialIsValid(String credential) { true }
}
class Fizz {}
abstract class FizzResource {
abstract List<Fizz> getAllFizzes(String credential)
abstract int getFizzById(String credential, Long id)
abstract void considerTheLillies(buzz)
static createFizzResource(authorized) {
def auth = new AuthorizingResource()
def authorize = { auth.authorize it; authorized << it }
return [
getAllFizzes : { String credential -> ['fizz list'] },
getFizzById : { String credential, Long id -> 42 },
considerTheLillies : { buzz -> }
]
.collectEntries { entry ->
entry.key.toLowerCase().contains('fizz') ?
[(entry.key) : { Object[] args ->
authorize(args[0]); entry.value(*args)
}] :
entry
} as FizzResource
}
}
测试:
def authorized = []
def fizz = FizzResource.createFizzResource(authorized)
assert authorized == []
assert fizz.getAllFizzes('getAllFizzes cred') == ['fizz list']
fizz.considerTheLillies null
assert authorized == ['getAllFizzes cred']
assert fizz.getFizzById('fizz by id cred', 90l) == 42
assert authorized == ['getAllFizzes cred', 'fizz by id cred']
请注意,authorized
列表非常愚蠢,仅用于assert
目的。