invokeMethod from Groovy with no parameters - groovy

I have some Java code that seemed to work fine:
/**
* Helper method
* 1. Specify args as Object[] for convenience
* 2. No error if method not implemented
* (GOAL: Groovy scripts as simple as possible)
*
* #param name
* #param args
* #return
*/
Object invokeGroovyScriptMethod(String name, Object[] args) {
Object result = null;
try {
result = groovyObject.invokeMethod(name, args);
} catch (exception) { // THIS HAS BEEN GROVIED...
if (exception instanceof MissingMethodException) {
if (log.isDebugEnabled()) {
log.debug("invokeGroovyScriptMethod: ", exception);
}
} else {
rethrow exception;
}
}
return result;
}
Object invokeGroovyScriptMethod(String name) {
return invokeGroovyScriptMethod(name, [ null ] as Object[]);
}
Object invokeGroovyScriptMethod(String name, Object arg0) {
return invokeGroovyScriptMethod(name, [ arg0 ] as Object[]);
}
Object invokeGroovyScriptMethod(String name, Object arg0, Object arg1) {
return invokeGroovyScriptMethod(name, [ arg0, arg1 ] as Object[]);
}
but I am having problems with the method:
Object invokeGroovyScriptMethod(String name) {
return invokeGroovyScriptMethod(name, [ null ] as Object[]);
}
groovy.lang.MissingMethodException: No signature of method: MyClass.getDescription() is applicable for argument types: (null) values: [null]
Possible solutions: getDescription(), setDescription(java.lang.Object)
Any hints?
Thank you
Misha

I had a quick go (getting rid of the log bit and replacing it with a println as I didn't have the logs set up in my tests), and I came up with this that doesn't require the overloaded versions of invokeGroovyScriptMethod:
Object invokeGroovyScriptMethod( String name, Object... args = null ) {
try {
args ? groovyObject."$name"( args.flatten() ) : groovyObject."$name"()
} catch( exception ) {
if( exception instanceof MissingMethodException ) {
println "invokeGroovyScriptMethod: $exception.message"
} else {
throw exception;
}
}
}
groovyObject = 'hi'
assert 'HI' == invokeGroovyScriptMethod( 'toUpperCase' )
assert 'i' == invokeGroovyScriptMethod( 'getAt', 1 )
assert '***hi' == invokeGroovyScriptMethod( 'padLeft', 5, '*' )
// Assert will pass (as we catch the exception, print the error and return null)
assert null == invokeGroovyScriptMethod( 'shouldFail' )
edit
Just read the question again, and you say this is a Java class? But then the catch seems to point to this being Groovy code...
I fear I may have sent you down the wrong path if this is Java...

Related

Null and empty check in one go in groovy

Can someone please clarify below issue.
Below validation throw NULL pointer error when pass null in myVar. It is because of !myVar.isEmpty()
if (myVar!= null || !myVar.isEmpty() ) {
some code///
}
Below works though as expected,
if (myVar!= null) {
if (!myVar.isEmpty()) {
some code///
}
Any other way of having both steps together.
If .isEmpty() is used on a string, then you can also just use Groovy
"truth" directly, as null and also empty strings are "false".
[null, "", "ok"].each{
if (it) {
println it
}
}
// -> ok
if ( myVar!= null && !myVar.isEmpty() ) {
//some code
}
the same as
if ( !( myVar== null || myVar.isEmpty() ) ) {
//some code
}
and to make it shorter - it's better to add method like hasValues
then check could be like this:
if( myVar?.hasValues() ){
//code
}
and finally to make it groovier - create a method boolean asBoolean()
class MyClass{
String s=""
boolean isEmpty(){
return s==null || s.length()==0
}
boolean asBoolean(){
return !isEmpty()
}
}
def myVar = new MyClass(s:"abc")
//in this case your check could be veeery short
//the following means myVar!=null && myVar.asBoolean()==true
if(myVar) {
//code
}

In YamlDotNet: Is there a way to output a null value as an empty string in a sequence?

When writing a sequence in an IYamlTypeConverter you might use some code like this:
public class MyObjectConverter : IYamlTypeConverter {
public MyObjectConverter() {}
public bool Accepts(Type type) { return typeof(IMyObject) == type || typeof(IMyObject[]) == type; }
public object ReadYaml(IParser parser, Type type) { return null; }
public void WriteYaml(IEmitter emitter, object value, Type type) {
var itemVal = value as IMyObject;
if (itemVal != null)
emitter.Emit(new Scalar(itemVal.GetID()));
else {
var arrayVal = value as IMyObject[];
emitter.Emit(new SequenceStart(null, null, true, SequenceStyle.Block));
if (arrayVal != null) {
foreach (var item in arrayVal)
if (item != null) emitter.Emit(new Scalar(item.GetID()));
else emitter.Emit(new Scalar("null"));
}
emitter.Emit(new SequenceEnd());
}
}
}
By calling emitter.Emit(new Scalar("null")) you would get a 'null' entry in the sequence, but if you leave the serialization up to YamlDotNet, it would be serialized as '' (empty string).
How do you output a null value in a sequence as an empty string when writing a custom IYamlTypeConverter?
One way to achieve this is to create a custom IEventEmitter that will add this logic:
public class NullStringsAsEmptyEventEmitter : ChainedEventEmitter
{
public NullStringsAsEmptyEventEmitter(IEventEmitter nextEmitter)
: base(nextEmitter)
{
}
public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
{
if (eventInfo.Source.Type == typeof(string) && eventInfo.Source.Value == null)
{
emitter.Emit(new Scalar(string.Empty));
}
else
{
base.Emit(eventInfo, emitter);
}
}
}
You then register it like this:
var serializer = new SerializerBuilder()
.WithEventEmitter(nextEmitter => new NullStringsAsEmptyEventEmitter(nextEmitter))
.Build();
Here's a fiddle with this code
It seems you can represent a null value simply with '~', according to http://www.yaml.org/refcard.html

How to build a reinitializable lazy property in Groovy?

This is what I'd like to do:
class MyObject {
#Lazy volatile String test = {
//initalize with network access
}()
}
def my = new MyObject()
println my.test
//Should clear the property but throws groovy.lang.ReadOnlyPropertyException
my.test = null
//Should invoke a new initialization
println my.test
Unfortunately lazy fields are readonly fields in Groovy and clearing the property leads to an exception.
Any idea how to make a lazy field reinitializable without reimplementing the double checking logic provided by the #Lazy annotation?
UPDATE:
Considering soft=true (from the 1st answer) made me run a few tests:
class MyObject {
#Lazy() volatile String test = {
//initalize with network access
println 'init'
Thread.sleep(1000)
'test'
}()
}
def my = new MyObject()
//my.test = null
10.times { zahl ->
Thread.start {println "$zahl: $my.test"}
}
Will have the following output on my Groovy console after approx 1 sec:
init
0: test
7: test
6: test
1: test
8: test
4: test
9: test
3: test
5: test
2: test
This is as expected (and wanted). Now I add soft=trueand the result changes dramatically and it takes 10 seconds:
init
init
0: test
init
9: test
init
8: test
init
7: test
init
6: test
init
5: test
init
4: test
init
3: test
init
2: test
1: test
Maybe I'm doing the test wrong or soft=true destroys the caching effect completely. Any ideas?
Can't you use the soft attribute of Lazy, ie:
class MyObject {
#Lazy( soft=true ) volatile String test = {
//initalize with network access
}()
}
edit
With soft=true, the annotation generates a setter and a getter like so:
private volatile java.lang.ref.SoftReference $test
public java.lang.String getTest() {
java.lang.String res = $test?.get()
if ( res != null) {
return res
} else {
synchronized ( this ) {
if ( res != null) {
return res
} else {
res = {
}.call()
$test = new java.lang.ref.SoftReference( res )
return res
}
}
}
}
public void setTest(java.lang.String value) {
if ( value != null) {
$test = new java.lang.ref.SoftReference( value )
} else {
$test = null
}
}
Without soft=true, you don't get a setter
private volatile java.lang.String $test
public java.lang.String getTest() {
java.lang.Object $test_local = $test
if ( $test_local != null) {
return $test_local
} else {
synchronized ( this ) {
if ( $test != null) {
return $test
} else {
return $test = {
}.call()
}
}
}
}
So the variable is read-only. Not currently sure if this is intentional, or a side-effect of using soft=true though...
Edit #2
This looks like it might be a bug in the implementation of Lazy with soft=true
If we change the getter to:
public java.lang.String getTest() {
java.lang.String res = $test?.get()
if( res != null ) {
return res
} else {
synchronized( this ) {
// Get the reference again rather than just check the existing res
res = $test?.get()
if( res != null ) {
return res
} else {
res = {
println 'init'
Thread.sleep(1000)
'test'
}.call()
$test = new java.lang.ref.SoftReference<String>( res )
return res
}
}
}
}
I think it's working... I'll work on a bugfix

Groovy MetaProgramming - intercept all method even missing ones

I'd like to intercept all method (instance and static) of a class even the missing ones.
Let say that :
class SomeClass {
def methodMissing(String name, args) {
if(name == "unknownMethod"){
return "result from unknownMethod"
}
else throw new MissingMethodException(name, delegate, args)
}
}
SomeClass.metaClass.static.invokeMethod = { methodName, args ->
println "Before"
def result = delegate.metaClass.invokeMethod(delegate, methodName, *args)
println "After"
return result
}
new SomeClass().with{ sc ->
sc.unknownMethod() //throw the MissingMethodExcept
}
This works well for method that are implemented by the class but when it's a method handled by methodMissing, I get a MissingMethodException...
How would you do that?
Thanks in advance
I think you need to catch the non static invokeMethod as well
Also, you need to go through getMetaMethod to call the original method or else you run the risk of stackoverflows.
Given the following:
class SomeClass {
String name
static String joinWithCommas( a, b, c ) {
[ a, b, c ].join( ',' )
}
String joinAfterName( a, b, c ) {
"$name : ${SomeClass.joinWithCommas( a, b, c )}"
}
def methodMissing(String name, args) {
if(name == "unknownMethod"){
return "result from unknownMethod"
}
else {
throw new MissingMethodException( name, SomeClass, args )
}
}
}
// Return a closure for invoke handler for a class
// with a given title (for the logging)
def invokeHandler = { clazz, title ->
{ String methodName, args ->
println "Before $methodName ($title)"
def method = clazz.metaClass.getMetaMethod( methodName, args )
def result = method == null ?
clazz.metaClass.invokeMissingMethod( delegate, methodName, args ) :
method.invoke( delegate, args )
println "After $methodName result = $result"
result
}
}
SomeClass.metaClass.invokeMethod = invokeHandler( SomeClass, 'instance' )
SomeClass.metaClass.static.invokeMethod = invokeHandler( SomeClass, 'static' )
new SomeClass( name:'tim' ).with { sc ->
sc.joinAfterName( 'a', 'b', 'c' )
sc.unknownMethod( 'woo', 'yay' )
sc.cheese( 'balls' )
}
I get the output:
Before with (instance)
Before joinAfterName (instance)
Before joinWithCommas (static)
After joinWithCommas result = a,b,c
After joinAfterName result = tim : a,b,c
Before unknownMethod (instance)
After unknownMethod result = result from unknownMethod
Before cheese (instance)
Exception thrown
groovy.lang.MissingMethodException: No signature of method: SomeClass.cheese() is applicable for argument types: (java.lang.String) values: [balls]

How to verify if an object has certain property?

I want to use either a value of expected property or a specified default.
How to achieve this in groovy?
Let's look at the example:
def printName(object) {
//if object has initialized property 'name' - print 'name', otherwise print ToString
if (object<some code here>name && object.name) {
print object.name
} else {
print object
}
}
You can use hasProperty. Example:
if (object.hasProperty('name') && object.name) {
println object.name
} else {
println object
}
If you're using a variable for the property name, you can use this:
String propName = 'name'
if (object.hasProperty(propName) && object."$propName") {
...
}
Assuming your object is a Groovy class, you can use hasProperty in the object metaClass like so:
def printName( o ) {
if( o.metaClass.hasProperty( o, 'name' ) && o.name ) {
println "Printing Name : $o.name"
}
else {
println o
}
}
So, then given two classes:
class Named {
String name
int age
String toString() { "toString Named:$name/$age" }
}
class Unnamed {
int age
String toString() { "toString Unnamed:$age" }
}
You can create instance of them, and test:
def a = new Named( name: 'tim', age: 21 )
def b = new Unnamed( age: 32 )
printName( a )
printName( b )
Which should output:
Printing Name : tim
toString Unnamed:32
You can write your own method via meta-programming:
class Foo {
def name = "Mozart"
}
def f = new Foo()
Object.metaClass.getPropertyOrElse = { prop, defaultVal ->
delegate.hasProperty(prop) ? delegate."${prop}" : defaultVal
}
assert "Mozart" == f.getPropertyOrElse("name", "")
assert "Salzburg" == f.getPropertyOrElse("city", "Salzburg")
If I simply want to assert that an object has some property, I just test the following:
assertNotNull(myObject.hasProperty('myProperty').name)
If myObject does not have myProperty the assertion will fail with a null pointer exception:
java.lang.NullPointerException: Cannot get property 'name' on null object

Resources