Add GroovyInterceptable section
Project: http://git-wip-us.apache.org/repos/asf/incubator-groovy/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-groovy/commit/2d42a54d Tree: http://git-wip-us.apache.org/repos/asf/incubator-groovy/tree/2d42a54d Diff: http://git-wip-us.apache.org/repos/asf/incubator-groovy/diff/2d42a54d Branch: refs/heads/master Commit: 2d42a54df73b6ca0410d10b1ac5fdb60fe23edfd Parents: 16b4221 Author: Maksym Stavytskyi <stavyts...@gmail.com> Authored: Mon Mar 30 01:53:18 2015 +0300 Committer: pascalschumacher <pascalschumac...@gmx.net> Committed: Sun May 3 18:35:30 2015 +0200 ---------------------------------------------------------------------- src/spec/doc/core-metaprogramming.adoc | 40 +++++++++++++++++++- .../metaprogramming/InterceptableTest.groovy | 20 ++++++++++ .../InterceptionThroughMetaClassTest.groovy | 25 ++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/2d42a54d/src/spec/doc/core-metaprogramming.adoc ---------------------------------------------------------------------- diff --git a/src/spec/doc/core-metaprogramming.adoc b/src/spec/doc/core-metaprogramming.adoc index 68e4e33..81d1c04 100644 --- a/src/spec/doc/core-metaprogramming.adoc +++ b/src/spec/doc/core-metaprogramming.adoc @@ -150,7 +150,45 @@ performance. `methodMissing` and `propertyMissing` that deal with static methods and properties can be added via the <<core-metaprogramming.adoc#metaprogramming_emc,ExpandoMetaClass>>. -=== GroovyInterceptable (TBD) +=== GroovyInterceptable +`GroovyInterceptable` interface is marker interface that extends `GroovyObject` and is used to notify groovy runtime that all methods should be intercepted through the method dispatcher mechanism of groovy runtime. + +[source, groovy] +---- +package groovy.lang; + +public interface GroovyInterceptable extends GroovyObject { + +} +---- +When groovy object implements the `GroovyInterceptable` interface, then its `invokeMethod()` is called for any method's calls. Below you can see a simple example of object of this type. + +//TODO Add information about println method. Default groovy object we cannot use with `GroovyInterceptable` interface becaues calling these methods will be intercepted too and we will have `StackOverflowError`. + +[source,groovy] +---- +include::{projectdir}/src/spec/test/metaprogramming/InterceptableTest.groovy[tags=groovy_interceptable_object_example,indent=0] +---- + +Next piece of code is test which shows that both calls of existed and nonexisted methods will return the same value. + +[source,groovy] +---- +include::{projectdir}/src/spec/test/metaprogramming/InterceptableTest.groovy[tags=groovy_interceptable_test,indent=0] +---- + +[NOTE] +We cannot use default groovy methods like as `println` because this methods are injected to all groovy objects so they will be intercepted too. + +If we want to intercept all methods call but don't want to implement `GroovyInterceptable` interface we can implement `invokeMethod()` on an object's `MetaClass`. This approach works for both types POGO and POJO. + +[source,groovy] +---- +include::{projectdir}/src/spec/test/metaprogramming/InterceptionThroughMetaClassTest.groovy[tags=meta_class_interception,indent=0] +---- + +[NOTE] +Additional information about `MetaClass` you can find in the <<core-metaprogramming.adoc#_metaclasses_tbd,MetaClasses>> topic. [[categories]] === Categories http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/2d42a54d/src/spec/test/metaprogramming/InterceptableTest.groovy ---------------------------------------------------------------------- diff --git a/src/spec/test/metaprogramming/InterceptableTest.groovy b/src/spec/test/metaprogramming/InterceptableTest.groovy new file mode 100644 index 0000000..3950e74 --- /dev/null +++ b/src/spec/test/metaprogramming/InterceptableTest.groovy @@ -0,0 +1,20 @@ +package metaprogramming + +// tag::groovy_interceptable_test[] +class InterceptableTest extends GroovyTestCase { + void testCheckInterception() { + def interception = new Interception() + assertEquals interception.definedMethod(), interception.someMethod() + } +} +// end::groovy_interceptable_test[] + +// tag::groovy_interceptable_object_example[] +class Interception implements GroovyInterceptable { + def definedMethod() {} + @Override + def invokeMethod(String name, Object args) { + 'invokedMethod' + } +} +// end::groovy_interceptable_object_example[] \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/2d42a54d/src/spec/test/metaprogramming/InterceptionThroughMetaClassTest.groovy ---------------------------------------------------------------------- diff --git a/src/spec/test/metaprogramming/InterceptionThroughMetaClassTest.groovy b/src/spec/test/metaprogramming/InterceptionThroughMetaClassTest.groovy new file mode 100644 index 0000000..133754c --- /dev/null +++ b/src/spec/test/metaprogramming/InterceptionThroughMetaClassTest.groovy @@ -0,0 +1,25 @@ +package metaprogramming + +import groovy.xml.Entity + +// tag::meta_class_interception[] +class InterceptionThroughMetaClassTest extends GroovyTestCase { + void testPOJOMetaClassInterception() { + String invoking = 'ha' + invoking.metaClass.invokeMethod = {String name, Object args -> + 'invoked' + } + assert invoking.length() == 'invoked' + assert invoking.someMethod() == 'invoked' + } + + void testPOGOMetaClassInterception() { + Entity entity = new Entity('Hello') + entity.metaClass.invokeMethod = {String name, Object args -> + 'invoked' + } + assert entity.build(new Object()) == 'invoked' + assert entity.someMethod() == 'invoked' + } +} +// end::meta_class_interception[]