Groovy method reference for multiple instances - groovy

I am migrating from Java to Groovy and having an issue with method references.
In Java, I could do this:
Function<Bean, String> f = Bean::method;
String s = f.apply(new Bean());
I want to implement the same functionality in Groovy. I tried doing:
Function f = Bean.&method
Sting s = f.apply new Bean()
But I got an exception, on the f.apply line:
groovy.lang.MissingMethodException: No signature of method: Bean.method() is applicable for argument types: (Bean) values: [Bean#17483c58]
I know I can do the following to get the method reference for an instance method, but I want to get a generic method for any instance.
MethodClosure f = bean.&method
String s = f()
I want to use this to use the EasyBind library. It allows you to select a JavaFX property with a Function reference. You might have a hierarchy of classes and properties, and to select them, you might do:
property.bind(EasyBind.select(root).select(Root::branch).selectObject(Branch::leaf));
So when any of the values in the tree change, property get's updated with the correct value.
I am able to replace the Bean.&method with {bean -> bean.method} and that works fine. In Java, the Bean::method is actually an alias-type thing for bean -> bean.method.

You can use:
MethodClosure f = { it.method }
String s = f()

Related

Nomin automap causes infinite loop

I am using Nomin for mapping tasks. As taken from the documentation of Nomin it should be able to map fields with the same name by itself in case automapping has been activated. When activating it, it causes an infinite loop exception.
I have the following:
mappingFor a: CoinsOnMarketPlace, b: Coin
// automap() // when deactivated it works fine, when activated infinite loop
a.coin.name = b.name
a.coin.rank = b.rank
a.priceUSD = b.priceUSD // Could be automapped
a.priceBTC = b.priceBTC // Could be automapped
...
Exception:
org.nomin.core.NominException: ./net/hemisoft/ccm/repository/coinmarketcap2coin.groovy: Recursive mapping rule a = b causes infinite loop!
One thing worth adding regarding your use case - this Recursive mapping rule a = b causes infinite loop! exception is thrown because you use groovy classes in your mapping rule. Nomin uses ReflectionIntrospector and what's important:
It performs getting/setting properties using accessor methods which are called through the Java reflection mechanism. ReflectionIntrospector uses supplied NamingPolicy instance to determine accessor methods. JbNamingPolicy is used by default, this implementation cerresponds the JavaBeans convention. Its InstanceCreator named ReflectionInstanceCreator instantiates objects using Class.newInstance().
Source: http://nomin.sourceforge.net/introspectors.html
A simple Groovy class like:
class Entity {
String name
String somethingElse
}
gets compiled to a Java class that implements GroovyObject providing following methods:
public interface GroovyObject {
Object invokeMethod(String var1, Object var2);
Object getProperty(String var1);
void setProperty(String var1, Object var2);
MetaClass getMetaClass();
void setMetaClass(MetaClass var1);
}
In this case ReflectionInstanceCreator combined with automap() resolves following mappings:
a.property = b.property
and
a = b
where a = b mapping comes from MetaClass getMetaClass() getter method I suppose, because there is no mapping like a.metaClass = b.metaClass resolved. a.property = b.property gets resolved because of Object getProperty(String var1) method.
Solution
This problem can be solved by specifying explicitly ExplodingIntrospector for your mapping script that:
It performs getting/setting properties using a class field immediately through through the Java reflection mechanism and may be useful in case when domain object don't provide accessors for their properties. Supplied instance creator is ReflectionInstanceCreator.
Source: http://nomin.sourceforge.net/introspectors.html
All you have to do is to add
introspector exploding
right below mappingFor a: ..., b: ... header. For example:
import mypackage.Entity
import mypackage.EntityDto
mappingFor a: Entity, b: EntityDto
introspector exploding
automap()
a.test2 = b.test1
Tested with two Groovy classes, worked like a charm. Hope it helps.

Groovy - Set your own property of an Integer

I just started to learn Groovy and wondering if you can set your own property for an integer. For example,
def a = 34.5.plus(34.34)
def b = 5.64.minus(3.43)
def c = 12.64.multiply(33.43)
In the above there are certain methods like plus minus and multiply
What should I do if I want to define some of my own methods for integers like that.
I searched Google but couldn't find much about it.
Sure, you can just add methods to the metaClass of Integer.
Here's an example:
Integer.metaClass.zeds = { -> 'z' * delegate }
assert 3.zeds() == 'zzz'
You can also add methods to a single instance of integer should you wish to, ie:
Integer num = 4
num.metaClass.halved = { -> delegate / 2.0 }
assert num.halved() == 2.0
You can also add methods to classes via Extension Methods a good explanation of which can be found over here
It should be noted (as you originally tagged this question as Java) that obviously, Java code will have no knowledge of these things, as it doesn't know about the metaClass
Use groovy meta programming, this allows you to create dynamic method creation atruntime in the class that you want to place in .
bydefault if a method is not found methodmissing exception throws , this is where groovy allows you add method at runtime for more reference use the below comprehensive link
http://groovy-lang.org/metaprogramming.html
If this answer helps , dont forget to click answered.

Vala: Pass String as Class

Scenario:
I have x number of classes. Lets say 10; Each class does different UI Functions. When a user loads a file, that extension tells the program the classname to load; but it's in the form of a string.
Is there anyway to pass a string off as a classname? Something to the effect of.
var classname = "Booger";
var nose = new classname(){ //classname really means "Booger"
//Do Operation
}
You can reflect a type by name using var t = Type.from_name(classname);, however, this works on all types, including enums and structs and it might be the type Type.INVALID. You should probably do some checks, like t.is_a(typeof(MyParentClass)).
You can then instantiate a copy using var obj = Object.new(t);. The whole thing would look like:
var classname = "Booger";
var t = Type.from_name(classname);
if (t.is_a(typeof(MyParentClass)))
return Object.new(t);
else
return null;
It's also worth noting that the run-time type names have the namespace prepended, so you might want to do "MyNs" + classname. You can check in either the generated C or doing typeof(MyClass).name().
I've had the same problem as the OP in regards to getting an assertion error against null. If you take a look at the Glib documentation (in C) it mentions you have to register your class by actually specifying the class name first before you can actually use a string representation of your class name.
In other words you have to use your class first BEFORE you can instantiate a copy of your class with Glib.Type.from_name ("ClassName").
You can use your class first by instantiating a class instance or by getting type information for your class.
var type = typeof (MyClass);
var type_from_string = Type.from_name ("MyClass");
Furthermore, when you use Object.new to create a class there are two things you need to be aware of:
1) You need to cast the return value to get your specific class or base class.
var instance_of_my_class = Object.new (type) as MyClass;
2) Constructors for your class will no longer be called (I don't why). You will need to use the GObject style constructor inside your class:
construct {
pizza = 5;
}

Can I redefine String#length?

I'd like to re-implement a method of a Java class. For example, for "hi".length() to return 4. (How) Can I do that?
I know using SomeClass.metaClass I can get a reference to an existing method and define new (or overriding) method, but I can't seem to be able to do that for existing Java methods.
Using Groovy, you can replace any method (even those of final classes) with your own implementation. Method replacement in Groovy uses the meta-object protocol, not inheritance.
Here's the example you requested, i.e. how to make String.length() always return 4
// Redefine the method
String.metaClass.invokeMethod = { name, args ->
def metaMethod = delegate.metaClass.getMetaMethod(name, args)
def result = metaMethod.invoke(delegate, args)
name == 'length' ? 4 : result
}
// Test it
assert "i_do_not_have_4_chars".length() == 4
Seems like it could be possible by abusing String metaClass. But the attempt I've done so far in groovy console didn't led to the expected result :
def oldLength = String.metaClass.length
String.metaClass.length = { ->
return oldLength+10;
}
println "hi".length()
outputs the sad 2
I think you could take a look at Proxy MetaClass or Delegating metaClass.
If you did redefine it, it would only work in Groovy code. Groovy can't change the way Java code executes.
In Groovy, "hi".length() is roughly equivalent to this Java:
stringMetaClass.invokeMethod("hi","length");
Because Groovy doesn't actually call length directly, metaClass tricks work in Groovy code. But Java doesn't know about MetaClasses, so there is no way to make this work.
Although this question is very old I like to point out another way (at least for newer Groovy versions) .
The length() method in java.lang.String is implemented from java.lang.CharSequence interface. In order to reimplement the method using the String-metaClass you need to "override" the method in the metaClass of the interface first.
CharSequence.metaClass.length = { -> -1}
String.metaClass.length = { -> 4 }
assert "i_do_not_have_4_chars".length() == 4
The solution using String.metaClass.invokeMethod changes the behaviour of all String-methods and is problematic. For instance, simply invoking "asdf".size() leads to an exception on my setup.

how to access a EL variable and pass it as an argument to a function in EL?

I want to call a function on a bean with an argument passsed to it in jsp using EL.
The problem is it does not allow something like:
"${teacherBean.certificationFor(${particularField})"
the thing is i want to iterate over an array and call the function certificationFor for all the values in the array passed as an argument.
I am getting the values in array by:
So Basically i want to do something like:
${teacherBean.certificationFor(${particularField})
but i cant do that.
can i do this in any other way?
I am a newbie in EL . :)
Any help is appreciated.
Where exactly do you want to do that and for what? Just to get a value for display? At least, in standard EL prior to Java EE 6 you cannot pass method arguments like that. In JBoss-EL or in Java EE 6 EL you can do that. The syntax would then just have been:
${teacherBean.certificationFor(particularField)}
Note that you cannot nest EL expressions, an EL expression is already a whole expression at its own.
In standard EL implementations you can however access Map values by keys using the brace notation. Thus, if you for example have a Map<String, String> certifications where the keys corresponds the particularField and the values the associated value:
private Map<String, String> certifications = new HashMap<String, String>();
public Map<String, String> getCertificationFor() {
return this.certifications;
}
then you can use the following notation:
${teacherBean.certificationFor[particularField]}
this resolves behind the scenes to
teacherBean.getCertificationFor().get(particularField)
I think in the standard EL you don't have any options other than defining your functions wrapped in a EL function;
Read: http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPIntro7.html near the bottom of the
document;
but as BalusC mentioned already if you could use another EL implmentation if you have the ability to add that kind of dependency to your app
What about:
${teacherBean.certificationFor(particularField)}
If you are accessing a general functionality that is better expressed as a separate function, then you can write it as follows:
${certificationFor[teacherBean][particularField]}
where certificationFor maps to the CertificationFor class which extends ELMethod.java class. You implement the functionality in the result(Object[] args) method. The args to this method are the args that you passed to the ${certificationFor} object in EL.
public class CertificationFor extends ELMethod {
public Object result(Object[] args) {
TeacherBean teacherBean = (TeacherBean) args[0];
String property = (String) args[1];
// your implementation goes here
return ....;
}
}
The trick is to use your object as a chained map of maps, that is one way to pass multiple args to EL function.
If you are interested, you can see full code and code snippets here:
http://www.vineetmanohar.com/2010/07/how-to-pass-parameters-in-el-methods/

Resources