Top Description Inners Fields Constructors Methods
groovy.lang

public Class ExpandoMetaClass

extends MetaClassImpl
implements GroovyObject
Class Inheritance
All Implemented Interfaces
groovy.lang.GroovyObject
Imports
groovy.transform.stc.ClosureParams, .SimpleType, org.codehaus.groovy.reflection.CachedClass, .MixinInMetaClass, org.codehaus.groovy.runtime.DefaultCachedMethodKey, .DefaultGroovyMethods, .InvokerHelper, .MetaClassHelper, .MethodKey, org.codehaus.groovy.runtime.callsite.CallSite, .ConstructorMetaMethodSite, .PogoMetaClassSite, .PojoMetaClassSite, .StaticMetaClassSite, org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod, .ClosureStaticMetaMethod, .DefaultMetaClassInfo, .MethodSelectionException, .MixedInMetaClass, .MixinInstanceMetaMethod, .OwnedMetaClass, .ThreadManagedMetaBeanProperty, org.codehaus.groovy.util.FastArray, java.lang.reflect.Constructor, .Method, .Modifier, java.util.ArrayList, .Collection, .Collections, .HashSet, .LinkedHashSet, .List, .Map, .Set, java.util.concurrent.ConcurrentHashMap, java.util.concurrent.locks.Lock, .ReentrantReadWriteLock

ExpandoMetaClass is a MetaClass that behaves like an Expando, allowing the addition or replacement of methods, properties and constructors on the fly.

Some examples of usage:

// defines or replaces instance method:
metaClass.myMethod = { args -> }

// defines a new instance method
metaClass.myMethod << { args -> }

// creates multiple overloaded methods of the same name
metaClass.myMethod << { String s -> } << { Integer i -> }

// defines or replaces a static method with the 'static' qualifier
metaClass.'static'.myMethod = { args ->  }

// defines a new static method with the 'static' qualifier
metaClass.'static'.myMethod << { args ->  }

// defines a new constructor
metaClass.constructor << { String arg -> }

// defines or replaces a constructor
metaClass.constructor = { String arg -> }

// defines a new property with an initial value of "blah"
metaClass.myProperty = "blah"

ExpandoMetaClass also supports a DSL/builder like notation to combine multiple definitions together. So instead of this:

Number.metaClass.multiply = { Amount amount -> amount.times(delegate) }
Number.metaClass.div =      { Amount amount -> amount.inverse().times(delegate) }
You can also now do this:
Number.metaClass {
    multiply { Amount amount -> amount.times(delegate) }
    div      { Amount amount -> amount.inverse().times(delegate) }
}

ExpandoMetaClass also supports runtime mixins. While @Mixin allows you to mix in new behavior to classes you own and are designing, you can not easily mixin anything to types you didn't own, e.g. from third party libraries or from JDK library classes. Runtime mixins let you add a mixin on any type at runtime.

interface Vehicle {
    String getName()
}

// Category annotation style
@Category(Vehicle) class FlyingAbility {
    def fly() { "I'm the ${name} and I fly!" }
}

// traditional category style
class DivingAbility {
    static dive(Vehicle self) { "I'm the ${self.name} and I dive!" }
}

// provided by a third-party, so can't augment using Mixin annotation
class JamesBondVehicle implements Vehicle {
    String getName() { "James Bond's vehicle" }
}

// Can be added via metaClass, e.g.:
// JamesBondVehicle.metaClass.mixin DivingAbility, FlyingAbility
// Or using shorthand through DGM method on Class
JamesBondVehicle.mixin DivingAbility, FlyingAbility

assert new JamesBondVehicle().fly() ==
       "I'm the James Bond's vehicle and I fly!"
assert new JamesBondVehicle().dive() ==
       "I'm the James Bond's vehicle and I dive!"
As another example, consider the following class definitions:
class Student {
    List schedule = []
    def addLecture(String lecture) { schedule << lecture }
}

class Worker {
    List schedule = []
    def addMeeting(String meeting) { schedule << meeting }
}
We can mimic a form of multiple inheritance as follows:
class CollegeStudent {
    static { mixin Student, Worker }
}
new CollegeStudent().with {
    addMeeting('Performance review with Boss')
    addLecture('Learn about Groovy Mixins')
    println schedule
    println mixedIn[Student].schedule
    println mixedIn[Worker].schedule
}
Which outputs these lines when run:
[Performance review with Boss]
[Learn about Groovy Mixins]
[Performance review with Boss]
Perhaps some explanation is required here. The methods and properties of Student and Worker are added to CollegeStudent. Worker is added last, so for overlapping methods, its methods will be used, e.g. when calling schedule, it will be the schedule property (getSchedule method) from Worker that is used. The schedule property from Student will be shadowed but the mixedIn notation allows us to get to that too if we need as the last two lines show.

We can also be a little more dynamic and not require the CollegeStudent class to be defined at all, e.g.:

def cs = new Object()
cs.metaClass {
    mixin Student, Worker
    getSchedule {
        mixedIn[Student].schedule + mixedIn[Worker].schedule
    }
}
cs.with {
    addMeeting('Performance review with Boss')
    addLecture('Learn about Groovy Mixins')
    println schedule
}
Which outputs this line when run:
[Learn about Groovy Mixins, Performance review with Boss]
As another example, we can also define a no dup queue by mixing in some Queue and Set functionality as follows:
def ndq = new Object()
ndq.metaClass {
    mixin ArrayDeque
    mixin HashSet
    leftShift = { Object o  -> 
        if (!mixedIn[Set].contains(o)) {
            mixedIn[Queue].push(o)
            mixedIn[Set].add(o)
        }
    }
}
ndq << 1
ndq << 2
ndq << 1
assert ndq.size() == 2
As a final example, we sometimes need to pass such mixed in classes or objects into Java methods which require a given static type but the ExpandoMetaClass mixin approach uses a very dynamic approach based on duck typing rather than static interface definitions, so doesn't by default produce objects matching the required static type. Luckily, there is a mixins capability within ExpandoMetaClass which supports the use of Groovy's common 'as StaticType' notation to produce an object having the correct static type so that it can be passed to the Java method call in question. A slightly contrived example illustrating this feature:
class CustomComparator implements Comparator {
    int compare(Object a, b) { return a.size() - b.size() }
}

class CustomCloseable implements Closeable {
    void close() { println 'Lights out - I am closing' }
}

import static mypackage.IOUtils.closeQuietly
import static java.util.Collections.sort
def o = new Object()
o.metaClass.mixin CustomComparator, CustomCloseable
def items = ['a', 'bbb', 'cc']
sort(items, o as Comparator)
println items                // => [a, cc, bbb]
closeQuietly(o as Closeable) // => Lights out - I am closing

Further details

When using the default implementations of MetaClass, methods are only allowed to be added before initialize() is called. In other words you create a new MetaClass, add some methods and then call initialize(). If you attempt to add new methods after initialize() has been called, an error will be thrown. This is to ensure that the MetaClass can operate appropriately in multi-threaded environments as it forces you to do all method additions at the beginning, before using the MetaClass.

ExpandoMetaClass differs here from the default in that it allows you to add methods after initialize has been called. This is done by setting the initialize flag internally to false and then add the methods. Since this is not thread safe it has to be done in a synchronized block. The methods to check for modification and initialization are therefore synchronized as well. Any method call done through this meta class will first check if the it is synchronized. Should this happen during a modification, then the method cannot be selected or called unless the modification is completed.

Since
1.5

Nested and Inner Type Summary

Modifier and TypeClass and Description
private static interface
ExpandoMetaClass.Callable

For simulating closures in Java

private class
protected class
ExpandoMetaClass.ExpandoMetaConstructor

Handles the ability to use the left shift operator to append new constructors

protected class
ExpandoMetaClass.ExpandoMetaProperty

Instances of this class are returned when using the << left shift operator.

private static class
private class
private class

Field Summary

Modifier and TypeField and Description
private final boolean
private final Map<String, MetaProperty>
private static final String
private static final String
public static final String
private static final Class<T>[]
private final Map<MethodKey, MetaMethod>
private final Map<String, MetaProperty>
private final ConcurrentHashMap<K, V>
private static final String
private final Set<MetaMethod>
private boolean
private volatile boolean
public boolean
private ClosureStaticMetaMethod
private static final String
private static final String
private static final String
private static final String
private final Set<MixinInMetaClass>
private volatile boolean
private MetaClass
private static final String
private final Lock
private final ReentrantReadWriteLock
public static final String
private final Map<String, MetaProperty>
private final Lock
Inherited from groovy.lang.MetaClassImpl:
EMPTY_ARGUMENTSgetPropertyMethodINVOKE_METHOD_METHODinvokeMethodMethodisGroovyObjectisMapmetaMethodIndexMETHOD_MISSINGPROPERTY_MISSINGregistrysetPropertyMethodSTATIC_METHOD_MISSINGSTATIC_PROPERTY_MISSINGtheCachedClasstheClass

Constructor Summary

AccessConstructor and Description
public
ExpandoMetaClass(Class<T> theClass, boolean register, boolean allowChangesAfterInit, MetaMethod[] add)

public
ExpandoMetaClass(MetaClassRegistry registry, Class<T> theClass, boolean register, boolean allowChangesAfterInit, MetaMethod[] add)

public
ExpandoMetaClass(Class<T>
The class that the MetaClass applies to
theClass
)

Constructs a new ExpandoMetaClass instance for the given class

public
ExpandoMetaClass(Class<T> theClass, MetaMethod[] add)

public
ExpandoMetaClass(Class<T>
The class that the MetaClass applies to
theClass
,
boolean
True if the MetaClass should be registered inside the MetaClassRegistry. This defaults to true and ExpandoMetaClass will effect all instances if changed
register
)

Constructs a new ExpandoMetaClass instance for the given class optionally placing the MetaClass in the MetaClassRegistry automatically

public
ExpandoMetaClass(Class<T> theClass, boolean register, MetaMethod[] add)

public
ExpandoMetaClass(Class<T>
The class that the MetaClass applies to
theClass
,
boolean
True if the MetaClass should be registered inside the MetaClassRegistry. This defaults to true and ExpandoMetaClass will effect all instances if changed
register
,
boolean
Should the meta class be modifiable after initialization. Default is false.
allowChangesAfterInit
)

Constructs a new ExpandoMetaClass instance for the given class optionally placing the MetaClass in the MetaClassRegistry automatically

Method Summary

Modifier and TypeMethod and Description
public void
private void
addSuperMethodIfNotOverridden(final MetaMethod metaMethodFromSuper)

public Object
protected void
checkInitalised()

Overrides groovy.lang.MetaClassImpl.checkInitalised.

checks if the initialisation of the class id complete.
public CallSite
public CallSite
createPogoCallCurrentSite(CallSite site, Class<T> sender, String name, Object[] args)

public CallSite
public CallSite
createPojoCallSite(CallSite site, Object receiver, Object[] args)

Overrides groovy.lang.MetaClassImpl.createPojoCallSite.

Create a CallSite
public CallSite
public ExpandoMetaClass
define(Closure<V> closure)

public static void
disableGlobally()

Call to disable the global use of ExpandoMetaClass

public static void
enableGlobally()

Call to enable global use of ExpandoMetaClass within the registry.

public MetaMethod
public List<MetaMethod>

Returns:

the expandoMethods
getExpandoMethods
()

Returns a list of expando MetaMethod instances added to this ExpandoMetaClass

public Collection<MetaProperty>

Returns:

the expandoProperties
getExpandoProperties
()

Returns a list of MetaBeanProperty instances added to this ExpandoMetaClass

public Collection<E>
public Class<T>

Returns:

The Java class enhanced by this MetaClass
getJavaClass
()

public MetaClass
getMetaClass()

Implements groovy.lang.GroovyObject.getMetaClass.

Returns the metaclass for a given class.
public MetaProperty

Returns:

The MetaProperty or null if it doesn't exist
getMetaProperty
(String
The name of the MetaProperty
name
)

Overrides groovy.lang.MetaClassImpl.getMetaProperty.

Implements groovy.lang.MetaObjectProtocol.getMetaProperty.

Looks up an existing MetaProperty by name
public List<MetaMethod>

Returns:

A list of MetaMethods
getMethods
()

Overrides groovy.lang.MetaClassImpl.getMethods.

Implements groovy.lang.MetaClass.getMethods.

Overrides the behavior of parent getMethods() method to make MetaClass aware of added Expando methods
public List<MetaProperty>
getProperties()

Overrides groovy.lang.MetaClassImpl.getProperties.

Implements groovy.lang.MetaClass.getProperties.

Get all the properties defined for this type
public Object
getProperty(String
the name of the property of interest
property
)

Overrides default groovy.lang.GroovyObject.getProperty.

Retrieves a property value.
public Object
getProperty(Class<T>
The java.lang.Class instance that requested the property
sender
,
Object
The Object which the property is being retrieved from
object
,
String
The name of the property
name
,
boolean
Whether the call is to a super class property
useSuper
,
boolean
??
fromInsideClass
)

Overrides groovy.lang.MetaClassImpl.getProperty.

Implements groovy.lang.MetaClass.getProperty.

Overrides default implementation just in case getProperty method has been overridden by ExpandoMetaClass
public Object
getProperty(Object
The Object which the property is being retrieved from
object
,
String
The name of the property
name
)

Overrides groovy.lang.MetaClassImpl.getProperty.

Implements groovy.lang.MetaObjectProtocol.getProperty.

Overrides default implementation just in case getProperty method has been overridden by ExpandoMetaClass
private String

Returns:

The property name equivalent
getPropertyForGetter
(String
The getter name
getterName
)

Returns a property name equivalent for the given getter name or null if it is not a getter

public String

Returns:

The property name equivalent
getPropertyForSetter
(String
The setter name
setterName
)

Returns a property name equivalent for the given setter name or null if it is not a getter

protected Object
public boolean
hasCustomStaticInvokeMethod()

Overrides groovy.lang.MetaClassImpl.hasCustomStaticInvokeMethod.

indicates is the meta class method invocation for static methods is done through a custom invoker object.
public boolean

Returns:

True if the method exists otherwise null
hasMetaMethod
(String
The name of the MetaMethod
name
,
Class<T>[]
The arguments to the meta method
args
)

Checks whether a MetaMethod for the given name and arguments exists

public boolean

Returns:

True it exists as a MetaProperty
hasMetaProperty
(String
The name of the MetaProperty
name
)

Returns true if the MetaClass has the given property

private boolean
public void
initialize()

Overrides groovy.lang.MetaClassImpl.initialize.

Implements groovy.lang.MetaClass.initialize.

Complete the initialisation process.
public Object
invokeConstructor(Object[]
The arguments to the constructor
arguments
)

Overrides groovy.lang.MetaClassImpl.invokeConstructor.

Implements groovy.lang.MetaObjectProtocol.invokeConstructor.

Invokes a constructor for the given arguments.
public Object
invokeMethod(String
the name of the method to call
name
,
Object
the arguments to use for the method call
args
)

Overrides default groovy.lang.GroovyObject.invokeMethod.

Invokes the given method.
public Object
invokeMethod(Class<T>
The java.lang.Class instance that invoked the method
sender
,
Object
The object which the method was invoked on
object
,
String
The name of the method
methodName
,
Object[]
The arguments to the method
originalArguments
,
boolean
Whether the method is a call to a super class method
isCallToSuper
,
boolean
Whether the call was invoked from the inside or the outside of the class
fromInsideClass
)

Overrides groovy.lang.MetaClassImpl.invokeMethod.

Implements groovy.lang.MetaClass.invokeMethod.

Overrides default implementation just in case invokeMethod has been overridden by ExpandoMetaClass
public Object
invokeStaticMethod(Object
An instance of the class returned by the getTheClass() method or the class itself
object
,
String
The name of the method
methodName
,
Object[]
The arguments to the method
arguments
)

Overrides groovy.lang.MetaClassImpl.invokeStaticMethod.

Implements groovy.lang.MetaObjectProtocol.invokeStaticMethod.

Overrides default implementation just in case a static invoke method has been set on ExpandoMetaClass
private boolean

Returns:

True if it is a javabean property method
isGetter
(String
True if its a Javabean property
name
,
CachedClass[]
The arguments
args
)

Returns true if the name of the method specified and the number of arguments make it a javabean property

protected boolean
isInitialized()

Overrides groovy.lang.MetaClassImpl.isInitialized.

Checks if the meta class is initialized.
public boolean
isModified()

Overrides groovy.lang.MetaClassImpl.isModified.

Implements groovy.lang.MutableMetaClass.isModified.

Returns whether this MetaClassImpl has been modified.
private static boolean
isPropertyName(String name)

Determine if this method name suffix is a legitimate bean property name.

public boolean
isSetter(String name, CachedClass[] args)

public static boolean
protected void
protected void
protected void
protected void
protected void
protected synchronized void
private void
public void
refreshInheritedMethods(Set<E>
A list of modified super ExpandoMetaClass
modifiedSuperExpandos
)

Called from ExpandoMetaClassCreationHandle in the registry if it exists to set up inheritance handling

private void
public void
registerBeanProperty(final String
The property name
property
,
final Object
The properties initial value
newValue
)

Registers a new bean property

private void
registerBeanPropertyForMethod(MetaMethod metaMethod, String propertyName, boolean getter, boolean isStatic)

public void
registerInstanceMethod(final MetaMethod metaMethod)

Registers a new instance method for the given method name and closure on this MetaClass

public void
protected void
registerStaticMethod(final String name, final Closure<V> callable)

protected void
registerStaticMethod(final String
The method name
name
,
final Closure<V>
The callable Closure
callable
,
final Class<T>[] paramTypes)

Registers a new static method for the given method name and closure on this MetaClass

public void
registerSubclassInstanceMethod(String name, Class<T> klazz, Closure<V> closure)

public void
public MetaMethod
retrieveConstructor(Object[] args)

Overrides groovy.lang.MetaClassImpl.retrieveConstructor.

This is a helper method added in Groovy 2.1.0, which is used only by indy.
protected void
public void
setMetaClass(MetaClass
the new metaclass
metaClass
)

Implements groovy.lang.GroovyObject.setMetaClass.

Allows the MetaClass to be replaced with a derived implementation.
public void
setProperty(String
the name of the property of interest
property
,
Object
the new value for the property
newValue
)

Overrides default groovy.lang.GroovyObject.setProperty.

Sets the given property to the new value.
public void
setProperty(Class<T>
The java.lang.Class instance that is mutating the property
sender
,
Object
The Object which the property is being set on
object
,
String
The name of the property
name
,
Object
The new value of the property to set
newValue
,
boolean
Whether the call is to a super class property
useSuper
,
boolean
Whether the call was invoked from the inside or the outside of the class.
fromInsideClass
)

Overrides groovy.lang.MetaClassImpl.setProperty.

Implements groovy.lang.MetaClass.setProperty.

Overrides default implementation just in case setProperty method has been overridden by ExpandoMetaClass
Inherited from groovy.lang.MetaClassImpl:
addMetaBeanPropertyaddMetaMethodaddMetaMethodToIndexaddNewInstanceMethodaddNewStaticMethodapplyPropertyDescriptorscheckIfGroovyObjectMethodchooseMethodclearInvocationCachescreateErrorMessageForAmbiguitycreatePogoCallCurrentSitecreateTransformMetaMethoddoChooseMostSpecificParamsdropMethodCachedropStaticMethodCachefindMethodInClassHierarchyfindOwnMethodfindPropertyInClassHierarchygetAdditionalMetaMethodsgetAttributegetAttributegetAttributegetClassInfogetClassNodegetEffectiveGetMetaPropertygetMetaMethodgetMetaMethodsgetMethodWithCachinggetMethodWithoutCachinggetRegistrygetStaticMetaMethodgetSuperClassesgetTheCachedClassgetTheClassgetVersionhandleMatcheshasCustomInvokeMethodhasPropertyincVersioninvokeMethodinvokeMethodinvokeMissingMethodinvokeMissingPropertyinvokeStaticMissingPropertyisGroovyObjectisPermissivePropertyAccessonMixinMethodFoundpickMethodreinitializerespondsTorespondsToretrieveConstructorretrieveStaticMethodselectConstructorAndTransformArgumentssetAttributesetAttributesetPermissivePropertyAccesssetPropertiessetPropertytoString