Updating groovy object fields from a map - groovy

In groovy we can easily create objects from maps and fill the corresponding fields automatically:
def myAddress = new Address([street:"King's street", number:"1200"])
Is it possible to also update an existing object from a map without recreating it? Something like...
myAddress.update([zip: "30555050", city: "London"])

You can use object."${variable}" accessors to do this:
map.each { key, value ->
object."${key}" = value
}
You can then create a method that does this and install that on Object.metaClass and it will be available everywhere:
#Canonical
class MapSet {
String name
int count
static def setAttributesFromMap(Object o, Map<String, Object> map) {
map.each { key, value ->
o."${key}" = value
}
}
static void main(String[] args) {
Object.metaClass.update = {
setAttributesFromMap delegate, it
}
def o = new MapSet([
name: "foo",
count: 5
])
assert o.name == "foo"
assert o.count == 5
o.update([
name: "bar",
count: 6
])
assert o.name == "bar"
assert o.count == 6
}
}

You can use InvokeHelper category and setProperties method, here is a short example:
import groovy.transform.EqualsAndHashCode
import groovy.transform.ToString
import org.codehaus.groovy.runtime.InvokerHelper
#EqualsAndHashCode
#ToString
class Address {
String street
String number
String city
}
Address mainAddress = new Address(street: 'Test', number: '2B', city: 'London')
use InvokerHelper, {
mainAddress.setProperties([street: 'Lorem', number: 'Ipsum'])
}
assert mainAddress.street == 'Lorem'
assert mainAddress.number == 'Ipsum'
assert mainAddress.city == 'London'
Although if you can avoid mutable objects, it's better for you. Otherwise you have to think about thread-safety to do not run into concurrency problems. You can use previous example to create a static method that expects 2 arguments: the existing object and a map of properties to update. In result you get a new instance that contains updated fields. Also you can make your class an immutable one.

After looking up/learning from Szymon's Excellent answer and finding a different way to invoke the helper, it seems like the answer can be simplified to:
InvokerHelper.setProperties(myAddress, [zip: "30555050", city: "London"])"
which is amazingly close to your requested
myAddress.update([zip: "30555050", city: "London"])
I added this as a comment to his question but it's so easy I thought it deserved a terse top-level answer of it's own.

Related

Is object deep-compare possible with Spock Framework?

How do I check for deep object equality with spock.
Lets say we have a super simple test that compares to identical person objects
def "A persons test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1 == person2
}
The test fails
Condition not satisfied:
person1 == person2
| | |
| | Person#6bedbc4d
| false
Person#57af006c
This looks like a very natural way of asserting equality.
One of the main reason to start using spock was to avoid having to write a lot of hamcrest boilerplate matchers code.
Spock has no built-in mechanism for performing deep Object comparison, because defining object equality is out of scope of any testing framework. You can do a various things.
1. Both classes are Groovy classes
If both your classes (Person and Address) are Groovy classes you can generate equals and hashCode methods using #EqualsAndHashCode annotation over both classes, like:
import groovy.transform.EqualsAndHashCode
import groovy.transform.TupleConstructor
import spock.lang.Specification
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1 == person2
}
#TupleConstructor
#EqualsAndHashCode
static class Person {
String name
Address address
}
#TupleConstructor
#EqualsAndHashCode
static class Address {
String city
}
}
This is just a convenient alternative for implementing both methods in Groovy.
2. Both classes are Java classes
If you want to compare both objects with == operator then you will have to define equals and hashCode methods in both classes, something like:
public final class Person {
private final String name;
private final Address address;
public Person(String name, Address address) {
this.name = name;
this.address = address;
}
public String getName() {
return name;
}
public Address getAddress() {
return address;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
return address != null ? address.equals(person.address) : person.address == null;
}
#Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (address != null ? address.hashCode() : 0);
return result;
}
static class Address {
private final String city;
public Address(String city) {
this.city = city;
}
public String getCity() {
return city;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return city != null ? city.equals(address.city) : address.city == null;
}
#Override
public int hashCode() {
return city != null ? city.hashCode() : 0;
}
}
}
In this example both methods were defined using IntelliJ IDEA "Generate equals and hashCode" command.
3. I can use Lombok!
If you don't want to define both methods manually (because e.g. you have to remember to change them anytime you modify your class fields) then you can use Lombok's #EqualsAndHashCode annotation that does something similar to Groovy's annotation, but can be applied to any Java class.
4. I want to keep default equals and hashCode methods
Well, in this case you can try various things:
You can try comparing both objects field-by-field, like:
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
person1.name == person2.name
and:
person1.address.city == person2.address.city
}
#TupleConstructor
static class Person {
String name
Address address
}
#TupleConstructor
static class Address {
String city
}
}
You can try using 3rd party tools like Unitils reflection assertion
That may sound bizarre, but you can compare JSON representation of both objects, something like:
import groovy.json.JsonOutput
import groovy.transform.TupleConstructor
import spock.lang.Specification
class PersonSpec extends Specification {
def "a person test"() {
setup:
def person1 = new Person("Foo", new Address("Bar"))
def person2 = new Person("Foo", new Address("Bar"))
expect:
new JsonOutput().toJson(person1) == new JsonOutput().toJson(person2)
}
#TupleConstructor
static class Person {
String name
Address address
}
#TupleConstructor
static class Address {
String city
}
}
Anyway, I would definitely suggest defining equals and hashCode in one way or another and simply use == operator. Hope it helps.
You can take advantage of Groovy's succinct map comparison syntax:
person1.properties == person2.properties
That only works for simple flat objects, not nested ones. You could adapt it like so:
person1.properties << ['address': person1.address.properties] == person2.properties << ['address': person2.address.properties]
...but JSON solution is more elegant at that point.
It seems, that you need to correct override your equals and hashcode methods.
In Groovy it can be done really easily, you need to use #Canonical annotation. It gives you more than equals and hashcode, buy the way.
I highly recommend you use Assertj for deep assertions. See below an example:
def "labels1 should be deeply equal to labels2"() {
when:
def labels1 = [new Label("labelA"), new Label("labelB")]
def labels2 = [new Label("labelB"), new Label("labelA")]
then:
assertThat(labels1)
.usingRecursiveComparison()
.ignoringCollectionOrder()
.isEqualTo(labels2)
}
Don't forget to add the Gradle dependency:
dependencies {
testImplementation "org.assertj:assertj-core:3.11.1"
}

Mapping enums to entities with Groovy

I have the following database table:
widget_types
------------
widget_type_id
widget_type_name
widget_type_alias
widget_type_description
This corresponds to the following Groovy entity class:
class WidgetType extends BaseLookupEntity {
Long id
String name
String alias
String description
}
In reality, WidgetType/widget_types really ought to be enums, because they are reference/lookup types with a small number of valid values:
RedWidget
SillyWidget
HappyWidget
BerserkingWidget
SausageWidget
For reasons outside the scope of this question, it is not really possible for me to OR/map the widget_types table to an enum. And so I have created a "helper enum":
enum WidgetTypeLookup {
Red,
Silly,
Happy,
Berserking,
Sausage
static WidgetTypeLookup toWidgetTypeLookup(WidgetType type) {
// TODO: ???
null
}
}
The idea here is that the JPA/OR layer will create WidgetType instances, but to be able to get real use out of them (type safety, etc.), I'd like to be able to convert them to WidgetTypeLookups:
// Inside some method...
WidgetType widgetType = getSomehowButStillNotSureWhichTypeItIs()
WidgetTypeLookup wtLookup = WidgetTypeLookup.toWidgetTypeLookup(widgetType)
switch(wtLookup) {
case Happy:
// etc...
}
So I'm struggling to find an efficient "Groovy way" of converting between the POGO type and the enum. Basically implementing the helper method. Any ideas?
I agree with the other answer that there might be better way to address your problem by improving OO design. Although I'll try to fit into your approach.
First - couldn't you just do it as follow and map the name as enum straight away?
class WidgetType extends BaseLookupEntity {
Long id
WidgetName name
String alias
String description
enum WidgetName {
Red,
Silly,
Happy,
Berserking,
Sausage
}
}
Second - the method you want to implement could be implemented like:
static WidgetTypeLookup toWidgetTypeLookup(WidgetType type) {
values().find {
it.name() == type.name
}
}
However:
the condition may need to be adjusted if names don't exactly match
you may need to handle somehow the case when there is no matching enum found
the name of the method should be rather something as fromWidgetType() then you'll have call like WidgetTypeLookup.fromWidgetType(widgetType) instead of redundant WidgetTypeLookup.toWidgetTypeLookup(widgetType)
Third - Even more groovy would be to implement custom type conversion as follows (I altered original classes names to reflect better what they are IMHO):
enum WidgetType {
Red,
Silly,
Happy,
Berserking,
Sausage
}
class WidgetTypeDetails {
Long id
String name
String alias
String description
Object asType(Class clazz) {
if (clazz == WidgetType) {
WidgetType.values().find {
it.name() == this.name
}
}
}
}
Then you can go like:
WidgetType widgetType = new WidgetTypeDetails(name: 'Red') as WidgetType
An enum is a limited number of fixed elements, unless that table have only fixed rows, Widget Red/Silly/etc should be subclasses.
You could implement the helper method inside the WidgetType class and operate specializations from an inner enum (though they can't reference the outer class)
class WidgetType {
Long id
String name
String alias
String description
enum Type {
RED,
SAUSAGE {
def install(container) {
"installing elongated component into $container"
}
},
SILLY,
HAPPY,
BERSERKING
def install(container) {
"installed ${name()} into $container"
}
}
Type getType() {
Type.values().find { it.name() == name }
}
}
red = new WidgetType(name: 'RED')
assert red.type.install("main container") ==
"installed RED into main container"
sausage = new WidgetType(name: 'SAUSAGE')
assert sausage.type.install("display") ==
"installing elongated component into display"
I think widget.install() is cooler and more OO (in a sense I don't need to pull the object guts to do something).
Another solution would be if WidgetType were an abstract class, and your ORM would instantiate the correct concrete type based on a specific value:
abstract class WidgetType {
Long id
String name
String alias
String description
abstract install(container)
enum Type {
RED(RedWidget),
SAUSAGE(SausageWidget),
}
static WidgetType from(type, properties) {
Type.values().find { it.name() == type }
.clazz
.newInstance(properties: properties)
}
}
class RedWidget extends WidgetType {
def install(container) { 'red installing into $container' }
}
class SausageWidget extends WidgetType {
def install(container) { 'elongated component installing into $container' }
}
The fake ORM:
class ORM {
def container = [
(1) : [
id: 1,
name: 'RED',
alias: 'my red alias',
description: 'this art red' ],
(2) : [
id: 2,
name: 'SAUSAGE',
alias: 'long component',
description: 'sausage component' ]
]
def get(id) {
container[it].with {
WidgetType.from(it.name, id)
}
}
}
Testing:
red = new ORM().get(1)
assert red.install('main') ==
'red installing into main'
sausage = new ORM().get(2)
assert sausage.install('display') ==
'elongated component installing into display'

How can I clone an Object (deep copy) in Dart?

Is there a Language supported way to make a full (deep) copy of an Object in Dart?
If multiple options exist, what are their differences?
Darts built-in collections use a named constructor called "from" to accomplish this. See this post: Clone a List, Map or Set in Dart
Map mapA = {
'foo': 'bar'
};
Map mapB = new Map.from(mapA);
No as far as open issues seems to suggest:
https://github.com/dart-lang/sdk/issues/3367
And specifically:
... Objects have identity, and you can only pass around references to them. There is no implicit copying.
Late to the party, but I recently faced this problem and had to do something along the lines of :-
class RandomObject {
RandomObject(this.x, this.y);
RandomObject.clone(RandomObject randomObject): this(randomObject.x, randomObject.y);
int x;
int y;
}
Then, you can just call copy with the original, like so:
final RandomObject original = RandomObject(1, 2);
final RandomObject copy = RandomObject.clone(original);
I guess for not-too-complex objects, you could use the convert library:
import 'dart:convert';
and then use the JSON encode/decode functionality
Map clonedObject = JSON.decode(JSON.encode(object));
If you're using a custom class as a value in the object to clone, the class either needs to implement a toJson() method or you have to provide a toEncodable function for the JSON.encode method and a reviver method for the decode call.
Unfortunately no language support. What I did is to create an abstract class called Copyable which I can implement in the classes I want to be able to copy:
abstract class Copyable<T> {
T copy();
T copyWith();
}
I can then use this as follows, e.g. for a Location object:
class Location implements Copyable<Location> {
Location({
required this.longitude,
required this.latitude,
required this.timestamp,
});
final double longitude;
final double latitude;
final DateTime timestamp;
#override
Location copy() => Location(
longitude: longitude,
latitude: latitude,
timestamp: timestamp,
);
#override
Location copyWith({
double? longitude,
double? latitude,
DateTime? timestamp,
}) =>
Location(
longitude: longitude ?? this.longitude,
latitude: latitude ?? this.latitude,
timestamp: timestamp ?? this.timestamp,
);
}
To copy an object without reference, the solution I found was similar to the one posted here, however if the object contains MAP or LIST you have to do it this way:
class Item {
int id;
String nome;
String email;
bool logado;
Map mapa;
List lista;
Item({this.id, this.nome, this.email, this.logado, this.mapa, this.lista});
Item copyWith({ int id, String nome, String email, bool logado, Map mapa, List lista }) {
return Item(
id: id ?? this.id,
nome: nome ?? this.nome,
email: email ?? this.email,
logado: logado ?? this.logado,
mapa: mapa ?? Map.from(this.mapa ?? {}),
lista: lista ?? List.from(this.lista ?? []),
);
}
}
Item item1 = Item(
id: 1,
nome: 'João Silva',
email: 'joaosilva#gmail.com',
logado: true,
mapa: {
'chave1': 'valor1',
'chave2': 'valor2',
},
lista: ['1', '2'],
);
// -----------------
// copy and change data
Item item2 = item1.copyWith(
id: 2,
nome: 'Pedro de Nobrega',
lista: ['4', '5', '6', '7', '8']
);
// -----------------
// copy and not change data
Item item3 = item1.copyWith();
// -----------------
// copy and change a specific key of Map or List
Item item4 = item1.copyWith();
item4.mapa['chave2'] = 'valor2New';
See an example on dartpad
https://dartpad.dev/f114ef18700a41a3aa04a4837c13c70e
With reference to #Phill Wiggins's answer, here is an example with .from constructor and named parameters:
class SomeObject{
String parameter1;
String parameter2;
// Normal Constructor
SomeObject({
this.parameter1,
this.parameter2,
});
// .from Constructor for copying
factory SomeObject.from(SomeObject objectA){
return SomeObject(
parameter1: objectA.parameter1,
parameter2: objectA.parameter2,
);
}
}
Then, do this where you want to copy:
SomeObject a = SomeObject(parameter1: "param1", parameter2: "param2");
SomeObject copyOfA = SomeObject.from(a);
Let's say you a have class
Class DailyInfo
{
String xxx;
}
Make a new clone of the class object dailyInfo by
DailyInfo newDailyInfo = new DailyInfo.fromJson(dailyInfo.toJson());
For this to work your class must have implemented
factory DailyInfo.fromJson(Map<String, dynamic> json) => _$DailyInfoFromJson(json);
Map<String, dynamic> toJson() => _$DailyInfoToJson(this);
which can be done by making class serializable using
#JsonSerializable(fieldRename: FieldRename.snake, includeIfNull: false)
Class DailyInfo{
String xxx;
}
It only works for object types that can be represented by JSON.
ClassName newObj = ClassName.fromMap(obj.toMap());
or
ClassName newObj = ClassName.fromJson(obj.toJson());
Trying using a Copyable interface provided by Dart.
there is an easier way for this issue
just use ... operator
for example, clone a Map
Map p = {'name' : 'parsa','age' : 27};
Map n = {...p};
also, you can do this for class properties.
in my case, I was needed to clone a listed property of a class.
So:
class P1 {
List<String> names = [some data];
}
/// codes
P1 p = P1();
List<String> clonedList = [...p.names]
// now clonedList is an unreferenced type
There is no built-in way of deep cloning an object - you have to provide the method for it yourself.
I often have a need to encode/decode my classes from JSON, so I usually provide MyClass fromMap(Map) and Map<String, dynamic> toJson() methods. These can be used to create a deep clone by first encoding the object to JSON and then decoding it back.
However, for performance reasons, I usually implement a separate clone method instead. It's a few minutes work, but I find that it is often time well spent.
In the example below, cloneSlow uses the JSON-technique, and cloneFast uses the explicitly implemented clone method. The printouts prove that the clone is really a deep clone, and not just a copy of the reference to a.
import 'dart:convert';
class A{
String a;
A(this.a);
factory A.fromMap(Map map){
return A(
map['a']
);
}
Map<String, dynamic> toJson(){
return {
'a': a
};
}
A cloneSlow(){
return A.fromMap(jsonDecode(jsonEncode(this)));
}
A cloneFast(){
return A(
a
);
}
#override
String toString() => 'A(a: $a)';
}
void main() {
A a = A('a');
A b = a.cloneFast();
b.a = 'b';
print('a: $a b: $b');
}
There's no API for cloning/deep-copying built into Dart.
We have to write clone() methods ourselves & (for better or worse) the Dart authors want it that way.
Deep copy Object /w List
If the Object we're cloning has a List of Objects as a field, we need to List.generate that field and those Objects need their own clone method.
Example of cloning method (copyWith()) on an Order class with a List field of objects (and those nested objects also have a copyWith()):
Order copyWith({
int? id,
Customer? customer,
List<OrderItem>? items,
}) {
return Order(
id: id ?? this.id,
customer: customer ?? this.customer,
//items: items ?? this.items, // this will NOT work, it references
items: items ?? List.generate(this.items.length, (i) => this.items[i].copyWith()),
);
}
Gunter mentions this here.
Note, we cannot use List.from(items) nor [...items]. These both only make shallow copies.
Dart does not share Memory within multiple threads (isolate), so...
extension Clone<T> on T {
/// in Flutter
Future<T> clone() => compute<T, T>((e) => e, this);
/// in Dart
Future<T> clone() async {
final receive = ReceivePort();
receive.sendPort.send(this);
return receive.first.then((e) => e as T).whenComplete(receive.close);
}
}
An example of Deep copy in dart.
void main() {
Person person1 = Person(
id: 1001,
firstName: 'John',
lastName: 'Doe',
email: 'john.doe#email.com',
alive: true);
Person person2 = Person(
id: person1.id,
firstName: person1.firstName,
lastName: person1.lastName,
email: person1.email,
alive: person1.alive);
print('Object: person1');
print('id : ${person1.id}');
print('fName : ${person1.firstName}');
print('lName : ${person1.lastName}');
print('email : ${person1.email}');
print('alive : ${person1.alive}');
print('=hashCode=: ${person1.hashCode}');
print('Object: person2');
print('id : ${person2.id}');
print('fName : ${person2.firstName}');
print('lName : ${person2.lastName}');
print('email : ${person2.email}');
print('alive : ${person2.alive}');
print('=hashCode=: ${person2.hashCode}');
}
class Person {
int id;
String firstName;
String lastName;
String email;
bool alive;
Person({this.id, this.firstName, this.lastName, this.email, this.alive});
}
And the output below.
id : 1001
fName : John
lName : Doe
email : john.doe#email.com
alive : true
=hashCode=: 515186678
Object: person2
id : 1001
fName : John
lName : Doe
email : john.doe#email.com
alive : true
=hashCode=: 686393765
// Hope this work
void main() {
List newList = [{"top": 179.399, "left": 384.5, "bottom": 362.6, "right": 1534.5}, {"top": 384.4, "left": 656.5, "bottom": 574.6, "right": 1264.5}];
List tempList = cloneMyList(newList);
tempList[0]["top"] = 100;
newList[1]["left"] = 300;
print(newList);
print(tempList);
}
List cloneMyList(List originalList) {
List clonedList = new List();
for(Map data in originalList) {
clonedList.add(Map.from(data));
}
return clonedList;
}
This works for me.
Use the fromJson and toJson from your Object's Class on JSON serializing
var copy = ObjectClass.fromJson(OrigObject.toJson());
make a helper class:
class DeepCopy {
static clone(obj) {
var tempObj = {};
for (var key in obj.keys) {
tempObj[key] = obj[key];
}
return tempObj;
}
}
and copy what you want:
List cloneList = [];
if (existList.length > 0) {
for (var element in existList) {
cloneList.add(DeepCopy.clone(element));
}
}
Let's say, you want to deep copy an object Person which has an attribute that is a list of other objects Skills. By convention, we use the copyWith method with optional parameters for deep copy, but you can name it anything you want.
You can do something like this
class Skills {
final String name;
Skills({required this.name});
Skills copyWith({
String? name,
}) {
return Skills(
name: name ?? this.name,
);
}
}
class Person {
final List<Skills> skills;
const Person({required this.skills});
Person copyWith({
List<Skills>? skills,
}) =>
Person(skills: skills ?? this.skills.map((e) => e.copyWith()).toList());
}
Keep in mind that using only this.skills will only copy the reference of the list. So original object and the copied object will point to the same list of skills.
Person copyWith({
List<Skills>? skills,
}) =>
Person(skills: skills ?? this.skills);
If your list is primitive type you can do it like this. Primitive types are automatically copied so you can use this shorter syntax.
class Person {
final List<int> names;
const Person({required this.names});
Person copyWith({
List<int>? names,
}) =>
Person(names: names ?? []...addAll(names));
}
The accepted answer doesn't provide an answer, and the highest-rated answer 'doesn't work' for more complex Map types.
It also doesn't make a deep copy, it makes a shallow copy which seems to be how most people land on this page. My solution also makes a shallow copy.
JSON-cloning, which a few people suggest, just seems like gross overhead for a shallow-clone.
I had this basically
List <Map<String, dynamic>> source = [{'sampledata', []}];
List <Map<String, dynamic>> destination = [];
This worked, but of course, it's not a clone, it's just a reference, but it proved in my real code that the data types of source and destination were compatible (identical in my case, and this case).
destination[0] = source[0];
This did not work
destination[0] = Map.from(source[0]);
This is the easy solution
destionation[0] = Map<String, dynamic>.from(source[0]);

Groovy: Is there a constructor called after the copy of parameters?

I have this code in Groovy:
class Person {
def age
Person () {
println age // null
}
}
def p = new Person ([age: '29'])
println p.age // 29
I need to read age value in constructor, but it isn't setted yet.
How can I do this?
Note: I don't want to use a init() method and call manually every time, like
class Person {
def age
def init() {
println age // now have 29
}
}
def p = new Person ([age: '29'])
p.init()
println p.age // 29
Link to GroovyConsole.
Thanks!
You can write a constructor like this:
class Person {
def age
Person(Map map) {
for (entry in map) {
this."${entry.key}" = entry.value
}
println age
}
}
If you're using groovy 1.8, take a look at the #TupleConstructor annotation, which will automatically build a constructor like the one above, as well as a list based one.
import groovy.transform.TupleConstructor
#TupleConstructor
class Person {
int age
}
p = new Person([age: 99])
assert p.age == 99

In groovy, is there a way to check if an object has a given method?

Assuming that I have an object someObj of indeterminate type, I'd like to do something like:
def value = someObj.someMethod()
Where there's no guarantee that 'someObj' implements the someMethod() method, and if it doesn't, just return null.
Is there anything like that in Groovy, or do I need to wrap that in an if-statement with an instanceof check?
Use respondsTo
class Foo {
String prop
def bar() { "bar" }
def bar(String name) { "bar $name" }
}
def f = new Foo()
// Does f have a no-arg bar method
if (f.metaClass.respondsTo(f, "bar")) {
// do stuff
}
// Does f have a bar method that takes a String param
if (f.metaClass.respondsTo(f, "bar", String)) {
// do stuff
}
Just implement methodMissing in your class:
class Foo {
def methodMissing(String name, args) { return null; }
}
And then, every time you try to invoke a method that doesn't exist, you will get a null value.
def foo = new Foo();
assert foo.someMethod(), null
For more information, take a look here: http://groovy.codehaus.org/Using+methodMissing+and+propertyMissing
You should be able to do something like:
SomeObj.metaClass.getMetaMethod("someMethod")
Or you can fall back to the good old Java reflection API.
You can achieve this by using getMetaMethod together with the safe navigation operator ?.:
def str = "foo"
def num = 42
def methodName = "length"
def args = [] as Object[]
assert 3 == str.metaClass.getMetaMethod(methodName, args)?.invoke(str, args);
assert null == num.metaClass.getMetaMethod(methodName, args)?.invoke(num, args);
if class :
MyClass.metaClass.methods*.name.any{it=='myMethod'}//true if exist
if object :
myObj.class.metaClass.methods*.name.any{it=='myMethod'}//true if exist
In very concise way you can use this:
if(someObj.&methodName){
//it means someObj has the method
}

Resources