Groovy Basics--metaclass Detailed

Source: Internet
Author: User
Tags groovy script

One, interception method invocation and parameter acquisition

Example 1:

Class myclass{def hello () {' Invoked Hello directly '} def invokeMethod (String name, Object args) {return ' unknown metho D $name (${args.join (', ')}) "}}def mine= new MyClass () assert mine.hello () = = ' invoked hello directly ' assert Mine.foo (" Mark ", +) = = ' Unknown method foo (Mark, 19) '

First we define a MyClass object in the groovy script, and any object in groovy is implemented Groovyobject and inherits Groovyobjectsupport, in the Groovyobject interface, We can see several methods, first, the Getmetaclass method and the Setmetaclass method, Metaclass used to support dynamic methods and dynamic parameter invocation. Another set of methods is the GetProperty and SetProperty methods, which are used to support the setting and assignment of dynamic parameters. Finally, there is a InvokeMethod method, which is used to invoke the dynamic method. After understanding the above concepts, we can understand that the InvokeMethod method of MyClass overrides the corresponding method in Groovyobjectsupport, so calling the non-predefined Foo method will go into the InvokeMethod implementation. The Hello method is predefined as usual.

Example 2:

Class MyClass implements Groovyinterceptable{def hello () {' invoked Hello () directly '}def InvokeMethod (String name, Object args) {"Invoked Method $name (${args.join (', ')})"}}def mine = new MyClass () assert mine.hello () = = ' invoked method he Llo () ' Assert Mine.foo (' Mark ', ' + ') = = ' invoked method foo (Mark, +) ' assert mine.&hello () = = ' invoked hello () directly '

The difference between this example and Example 1 is that it implements a groovyinterceptable interface, looking closely at the description of the interface, knowing that the class that implements the interface is called by default using the InvokeMethod method, regardless of whether the method is dynamically generated or when it is statically generated The 2nd difference is that if you want to invoke the method of the original definition number in this case, you need to work with the ' .& ' operator.

Example 3:

Class Myclass{def greeting = ' accessed greeting directly ' Object getProperty (String property) {"Read from property $propert Y "}void setProperty (String property, Object Newvlaue) {throw new Exception (" wrote to property $property ")}}def mine = new M  Yclass () assert mine.greeting = = ' Read from property greeting ' try{mine.greeting = ' Hi '}catch (e) {assert e.message = = ' wrote To property greeting '}assert [email protected] = = ' accessed greeting directly '

This example describes the property's get attribute, which is inherited when the method of setting and getting properties has been described in Example 1, and is not discussed here. By default, the values of properties are handled by Gpath (see Gpath specific concepts) by calling GetProperty and SetProperty. Similarly, if you really want to access the value of the parameter directly, you can use the '[email protected]' operator to work around it.

The property value is obtained by Gpath. Regardless of whether the attribute is in the class, there is no error in executing the 2 methods. However, for properties that do not exist in the class, avoid using the ' [email protected] ' operator, which throws MissingFieldException.

Example 4:

Class MyClass implements Groovyinterceptable{def greeting = ' accessed greeting ' def id = ' White: ' Object getProperty (String property) {Try{return [email protected] +//access field directly ' indirectly ' +[email protected] "$property"}catch (e) { Return "No such property $property"}}def hello (object[] args) {"Invoked Hello with (${args.join (', ')})"}def ID () {' Green: ' }def InvokeMethod (String name, Object args) {Try{return this.&id () +//call method directly ' indirectly ' +this.& "$ Name "(args)}catch (e) {return" No such method $name "}}}def mine = new MyClass () assert mine.greeting = = ' white:indirectly ac cessed greeting ' assert Mine.farewell = = ' No such property farewell ' Assert Mine.hello (1, ' B ', 3) = = ' green:indirectly invo ked Hello with (1, B, 3) ' Assert Mine.foo (' Mark ', ' + ') = = ' No such method foo '

The example is a merger of example 2,3, and he tells us that we can dynamically get parameters or dynamic methods by using the "[email protected] ' or ' .& ' method of defining variables in double quotes after the operator.

Second, Metaclass (class of Description Class)

Example 5:

public class Mymetaclass extends Delegatingmetaclass{mymetaclass (class ThisClass) {super (ThisClass)}object InvokeMethod (Object object, String methodName, object[] arguments) {"Mymetaclass: ${super.invokemethod (Object, MethodName, arguments)} "}}class a{def bark () {' a:invoked bark () '}def InvokeMethod (String name, Object args) {" A:missing $ Name (${args.join (', ')}) "}}def AMC = new Mymetaclass (a) amc.initialize () def a = new A () A.metaclass = Amcassert A.bark () = =  ' Mymetaclass:a: Invoked bark () ' Thread.Start {assert a.bark () = = ' Mymetaclass:a: invoked bark () '}assert new A (). Bark () = = ' A:invoked bark () ' assert a.bleet () = = ' a:missing bleet () '
The code for this example is longer, and the main meaning is that we can use the Metaclass property in any groovy object to change the behavior of the method call of that object. Groovy provides us with aDelegatingmetaclass to let us implement this feature.

This is done by first creating a custom Metaclass class that inherits from the Delegatingmetaclass, while implementing the constructor method, as well as the custom method invocation behavior (later content will be introduced, we can not only change the method behavior). Then we can wrap the target class that you want to change the behavior by using the Metaclass subclass that you created. Here is Class A. Then create the target class instance and set the Metaclass property in the target class. Subsequent method calls on the instance will be processed according to the processor that corresponds to the Metaclass property of the instance, in which case the Mymetaclass string is added before completing the method call itself.

but it is worth noting that 1. For another newly created instance of a, if no Metaclass attribute assignment is performed according to the original method definition; 2. Dynamically defined

method is not affected by the behavior change of the Metaclass method. See the last line of the example. 3. The above features are equally valid within a new thread.

Example 6:

InvokerHelper.instance.metaRegistry.setMetaClass (A, AMC)

The example is just a supplement to example 5, and we have mentioned that we can let Metaclass's behavior take effect on that instance by setting the Metaclass property for the target class instance. However, if you want to take effect within the scope of the class, you need to register it with the code above. After this registration, the metaclass behavior is given to all of the target classes, any time the example is created.

There is one more thing to note about this example. Imagine a situation where a target class instance is created, registered with the statement in Example 6, and then an instance of the target class is created. Which object will the behavior of metaclass take effect on? The answer is that both are in effect. This is crucial. Once the class scope Metaclass is registered, it takes effect for both created and newly created objects.

Note: instance for a high version of groovy Invokerhelper does not exist. You can call Metaregistry directly.

Example 7:

Import Org.codehaus.groovy.runtime.invokerhelper;public class Mymetaclass extends Delegatingmetaclass{mymetaclass ( Class Theclass) {super (Theclass)}object invokeconstructor (object[] arguments) {[]}}class a{}def AMC = new Mymetaclass (A) Amc.initialize () InvokerHelper.metaRegistry.setMetaClass (A,AMC) def A = new A () assert a.class = = Arraylistassert (a< <1<<2<<3). Size () = = 3

The previous example has slightly mentioned that metaclass can not only change the predefined method behavior. In this example, change the construction behavior as an example. The metaclass changes the construction behavior to create an array object. The subsequent operation is at a glance.

It is worth mentioning that theInvokeconstructor method is inherited from the Metaclass interface Metaobjectprotocol, and other methods may

is from a different inheritance tree, so you can see the method signature in Delegatingmetaclass. We can find a lot of invokexxx and getxxx methods, which means we can make changes to these metaclass behaviors. The main we can see there is the GetProperty method Invokeconstructor method, of course I am excited to find there is a Invokemissingmethod method, This approach seems to be a useful addition to the metaclass behavior in our example 5 that cannot handle dynamic definition methods.

Third, Expandometaclass

The following example is more, before giving an example, we need to clarify some of the details, you might think that we previously set metaclass for Groovyobject to change the behavior of the class instance, that is not set by default, what is this metaclass? In fact, whether you set or not set Metaclass it's metaclass are handlemetaclass type, but the difference is that, There is a Getadaptee method that returns the delegate attribute of the Metaclass type in Delegatingmetaclass, by default, this delegate will be Metaclassimpl type, But once you set the Metaclass property of the target class instance yourself, the delegate attribute is the one you set. The subject we're going to be following, That is, the title of this chapter Expandometaclass (a subclass of Metaclassimpl) is another delegate that is parallel to Metaclassimpl and the metaclass of custom, just this delegate, Features that support dynamic creation methods, and so on. Let's first introduce the example

Example 8:

Class a{string text}def a1= new A (text: ' ABCdefG ') assert a1.metaClass.adaptee.class = = MetaClassImplA.metaClass.inSameC  ASE = {-> text.touppercase ()}//triggers conversion of Metaclass of A to Expandometaclass//then adds new instance method ' Inuppercase ' to class//a.metaclass {}//def a2 = new A (text: ' Hijklmnop ') assert a2.metaClass.adaptee.class = = Expandomet Aclass//metaclass of A changed for instances created after conversion trigger Onlyassert a2.insamecase () = = ' Hijklmnop '//n ew method not Availableassert A1.metaClass.adaptee.class = = metaclassimpltry{println a1.insamecase ();} catch (e) {assert e in missingmethodexception}a.metaclass.inlowercase = {-> text.tolowercase ()}assert a2.inLowerCase () = = ' Hijklmnop '//replace the method definition with anotherA.metaClass.inSameCase = {-> text.tolowercase ()}assert A2 . insamecase () = = ' Hijklmnop '//add static Methodsa.metaclass. ' Static '. Insamecase = {it.tolowercase ()}assert a.insamecase (' qrstuvwxyz ') = = ' qrstuvwxyz '
The first few lines of code confirm that the default delegate (that is, the Metaclass attribute in Handlemetaclass) is Metaclassimpl. Then we call theThe A.metaclass {} method, which is located in Defaultgroovymethods, causes the delegate in the returned Handlemetaclass to be

type of Expandometaclass. So we can use that type of metaclass to do things for us. The same

a.metaclass.insamecase = {-> text.touppercase ()} method only when registering Metaclass as Expandometaclass

Add an instance method to it dynamically. At the same time we can learn in the last few lines of code that adding static methods dynamically is also possible.

A few points to note: 1. Only target objects created after switching delegate to Expandometaclass can support dynamic methods provided when switching. 2. The addition of dynamic methods has an overlay relationship.

Example 9:

Class A{}a.metaclass.character = ' Cat in the Hat ' def a1 = new A () assert a1.character = = ' Cat in the Hat ' Def ourproperties = Collections.synchronizedmap ([:]) A.metaclass.settype = {String value, ourproperties["${delegate}type"] = value} A.metaclass.gettype = {-ourproperties["${delegate}type"]}a1.type = ' hatted cat ' assert a1.type = ' hatted cat ' def A2 = new A () A.metaclass.constructor = {-New A ()}try{a2 = new A ()}catch (Error e) {assert E in Stackoverflowerror}a.metacl Ass.constructor = {String S, new A (character:s)}a2 = new A ("Thing one") a.metaclass. ' Changecharactertothingtwo ' = {-> delegate.character = ' Thing '}a2.character= ' Cat in the Hat ' A2.changecharactertothingtwo () assert a2.character = = ' Thing ' [' hatted Cat ', ' Thing ', ' Boy ', ' Girl ', ' mother '].each{ P-> A.metaclass. " Changetypeto${p} "= {-> delegate.type= p}}a2.changetypetoboy () assert a2.type = = ' Boy ' A2. ' Changetypetohatted Cat ' () assert a2.type = = ' hatted cat '

As a supplement to example 8, we can not only add methods dynamically, but also dynamically add properties and construct methods.

Example 10:


expandometaclass.enableglobally ()//call ' enableglobally ' method before adding to supplied classList.metaClass.sizeDoubled = {-> delegate.size () * 2}//add method to an interfacedef list = [] << 1 << ; 2assert list.sizedoubled () = = 4
This example is an introduction that tells us that we can not only dynamically add property methods to custom groovy objects, but we can also dynamically process objects that are not custom groovy provided. The method of handling methods and custom objects is exactly the same, the only difference is that we need additional definitionsexpandometaclass.enableglobally (), however, I found that the author used 1.8.1 version of Groovy If you remove the statement, it works.

So please follow the personal version of the reader to try.

Example 11:

Class Bird{def name = ' Tweety ' def twirp () {' I taught I saw a puddy cat '}}bird.metaclass.invokemethod = {name, args->de F metamethod = Bird.metaClass.getMetaMethod (name, args) Metamethod?metamethod.invoke (Delegate,args): ' No such method '} def a = new Bird () assert a.twirp () = = ' I taught I saw a puddy cat ' assert a.bleet () = = ' No such method ' Bird.metaClass.getPro Perty = {Name->def metaproperty = Bird.metaClass.getMetaProperty (name) Metaproperty?metaproperty.getproperty ( Delegate): ' No such property '}def B = new Bird () assert b.name = ' tweety ' assert b.filling = = ' No such property '

This example mainly shows that we can not only use the expando feature to add method attributes and constructor methods, but we can also overwrite existing methods. Finally, I want to emphasize that the Bird.metaclass returned is Expandometaclass we covered here Getmetamethod and

both the GetProperty and the InvokeMethod and GetProperty methods overwrite the method that corresponds to the Expandometaclass class and its parent class.

At this point, groovy's metaclass content has been introduced. This part of the content is very important in groovy. I would like to record it for future reference, and I hope it will be helpful to you.



Groovy Basics--metaclass Detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.