Groovy - can a method defined in an Interface have default values? - groovy

If the following is entered in Eclipse/STS (with groovy):
interface iFaceWithAnIssue {
def thisIsFine(a,b,c)
def thisHasProblems(alpha='va')
}
The only line that complains is the one trying to use a default value. I can not tell from the codehaus site if this is supported or not.
The IDE error is:
Groovy:Cannot specify default value for method parameter
So this makes me think it is not supported. As there will be multiple implementations, I wanted to use an interface here. I don't really need the default value in the interface, but there is an error trying to fulfill the interface contract if the implementation class then tries to default this argument. Is there any way?

No, you cannot.
When you define a default value, Groovy actually creates multiple methods in your class, so for example:
class Test {
void something( a=false ) {
println a
}
}
Actually creates
public void something(java.lang.Object a) {
this.println(a)
}
and
public void something() {
this.something(((false) as java.lang.Object))
}
This can't be done as it stands in Interfaces.
You could do:
interface iFaceWithAnIssue {
def thisHasProblems()
def thisHasProblems(alpha)
}
Then
class Test implements iFaceWithAnIssue {
// This covers both Inteface methods
def thisHasProblems(alpha='va') {
// do something
}
}

Related

Groovy execute code using custom annotation

I would like to execute a function (with parameters) through an annotation tag in a groovy script.
If we execute a method in our groovy script with this annotation it would print in the console (stderr) a custom message like:
warning: '<function_name>' is deprecated [[Use '<Deprecated.instead>' instead.][More info: '<Deprecated.more_info>']]
So, I have created a custom annotation like this
public #interface Deprecated {
public String instead() default null
public String more_info() default null
}
The goal is to use it like this:
def new_call() {
//new version of the method
}
#Deprecated(instead="new_call")
def call() {
//do something
}
In my example, it would output like this:
warning: 'call' is deprecated. Use 'new_call' instead.
I saw this post Groovy: How to call annotated methods, it's over 7 years old now but looks good so i'll look deeper.
I saw also Delegate.deprecated but i'm not sure if that's what i want
I'm not sure I am doing right. So if you have any advice or suggestions, I'll be happy to hear you.
Simple AOP Approach
This is very-very basic implementation with groovy out-of the box.
Deprecated Annotation
#Target([ElementType.METHOD])
#Retention(RetentionPolicy.RUNTIME)
#interface Deprecated {
String instead() default 'null'
String more_info() default 'null'
}
Class which should get this functionality
The class has to implement GroovyInterceptable - invokeMethod.
class SomeClass implements GroovyInterceptable {
#Override
def invokeMethod(String name, args) {
DeprecatedInterception.apply(this, name, args)
}
def new_call() {
println('new_call invoked')
}
#Deprecated(instead = 'new_call', more_info = '... the reason')
def depr_call() {
println('depr_call invoked')
}
}
Interception Util
import org.codehaus.groovy.reflection.CachedMethod
class DeprecatedInterception {
static apply(Object owner, String methodName, Object args) {
MetaMethod metaMethod = owner.metaClass.getMetaMethod(methodName, args)
Deprecated d = extractAnnotation(metaMethod)
if (d) {
println("warning: '$methodName' is deprecated. Use '${d.instead()}' instead. More info: '${d.more_info()}'")
}
// handle methods with var-args
metaMethod.isVargsMethod() ?
metaMethod.doMethodInvoke(owner, args) :
metaMethod.invoke(owner, args)
}
static Deprecated extractAnnotation(MetaMethod metaMethod) {
if (metaMethod instanceof CachedMethod) {
metaMethod.getCachedMethod()?.getAnnotation(Deprecated)
} else {
null
}
}
}
Simple Test
Just check that no exceptions/errors..
class TestWarnings {
#Test
void test() {
new SomeClass().with {
new_call()
depr_call()
}
}
}
Output:
new_call invoked
warning: 'depr_call' is deprecated. Use 'new_call' instead. More info: '... the reason'
depr_call invoked
Disclaimer
This should work for most cases, but has some limitations:
will not work for static methods (unless invoked on Object instance)
you have to implement GroovyInterceptable per each class, to apply
you might faced with some side-effects in some groovy syntax or features (at least I've found the issue with vararg methods invocation, but this already fixed)
So this should be tested and potentially improved before widely using for some production projects.
Other options:
Shortly, because implementation might be more complex (not sure, at least I not able to provide some example in a short time), but potentially this is more solid.
Adding AST Transformations.
Use some AOP library.

How to reference subclass from a static superclass method in Groovy

A simplified version of what I'm trying to do in Groovy:
class Animal {
static def echo() {
println this.name // ie "class.name"
}
}
class Dog extends Animal {
}
class Cat extends Animal {
}
Dog.echo()
Cat.echo()
// Output:
// => Animal
// => Animal
//
// What I want:
// => Dog
// => Cat
I think what I'm asking here is: when I call a static method on an object, and
the static method is defined in the object's superclass, is there a way to obtain
the actual type of the object?
A static method is not defined in the object context, but in the class context. You might get confused by the presence of this in the Groovy static method. However, it's only a syntactic sugar that eventually replaces this.name with Animal.class.name.
If you compile the Animal class from your example with a static compilation enabled, you will see that it compiles to the following Java equivalent (result after decompiling the .class file):
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
public class Animal implements GroovyObject {
public Animal() {
MetaClass var1 = this.$getStaticMetaClass();
this.metaClass = var1;
}
public static Object echo() {
DefaultGroovyMethods.println(Animal.class, Animal.class.getName());
return null;
}
}
You can see that the following line in the echo method:
DefaultGroovyMethods.println(Animal.class, Animal.class.getName());
operates directly on the Animal class name. So from the echo method perspective, it doesn't matter how many classes extend it. As long as those classes invoke echo method defined in the Animal class, you will always see Animal printed as a result.
And there is even more than that. If you use the following compiler configuration script:
config.groovy
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
ast(groovy.transform.TypeChecked)
}
and then compile the script (let's call it script.groovy) using this configuration option with the following command:
groovyc --configscript=config.groovy script.groovy
then you will see something like this after decompiling the .class file:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import groovy.lang.Binding;
import org.codehaus.groovy.runtime.InvokerHelper;
public class script extends groovy.lang.Script {
public script() {
}
public script(Binding context) {
super(context);
}
public static void main(String... args) {
InvokerHelper.runScript(script.class, args);
}
public Object run() {
Animal.echo();
return Animal.echo();
}
}
You can see that even though you have invoked Dog.echo() and Cat.echo() in your Groovy script, the compiler replaced these calls with the double Animal.echo() invocation. It happened because calling this static method on any other subclass does not make any difference.
Possible solution: applying double dispatch
There is one way to get the expected output - override echo static method in Dog and Cat class. I can assume that your real method may do something more than the exemplary echo method you have shown above, so you might need to call the super echo method from a parent class. But... there are two problems: (1) you can't use super.echo() in the static context, and (2) it doesn't solve the problem, because parent method still operates in the Animal class context.'
To solve this kind of issue you might want to mimic a technique called double dispatch. In short - when we don't have information about the caller in the method that was called, let's allow the caller to pass this information with the method call. Consider the following example:
import groovy.transform.CompileStatic
#CompileStatic
class Animal {
// This is a replacement for the previous echo() method - this one knows the animal type from a parameter
protected static void echo(Class<? extends Animal> clazz) {
println clazz.name
}
static void echo() {
echo(Animal)
}
}
#CompileStatic
class Dog extends Animal {
static void echo() {
echo(Dog)
}
}
#CompileStatic
class Cat extends Animal {
static void echo() {
echo(Cat)
}
}
Animal.echo()
Dog.echo()
Cat.echo()
This may sound like a boilerplate solution - it requires implementing echo method in each subclass. However, it encapsulates the echo logic in the method that requires Class<? extends Animal> parameter, so we can let every subclass to introduce their concrete subtype. Of course, this is not a perfect solution. It requires implementing echo method in each subclass, but there is no other alternative way. Another problem is that it doesn't stop you from calling Dog.echo(Animal) which will cause the same effect as calling Animal.echo(). This double dispatch like approach is more like introducing a shorthand version of echo method which uses the common static echo method implementation for simplicity.
I don't know if this kind of approach solves your problem, but maybe it will help you find a final solution.

Groovy Copying / Combining MetaMethods From Multiple Objects

I have two classes. At runtime, I want to "clone" the methods of one object, over to another. Is this possible? My failed attempt using leftshift is shown below.
(Note: I also tried currMethod.clone() with the same result.)
class SandboxMetaMethod2 {
String speak(){
println 'bow wow'
}
}
class SandboxMetaMethod1{
void leftShift(Object sandbox2){
sandbox2.metaClass.getMethods().each{currMethod->
if(currMethod.name.contains("speak")){
this.speak()
this.metaClass."$currMethod.name" = currMethod
this.speak()
}
}
}
String speak(){
println 'woof'
}
}
class SandboxMetaMethodSpec extends Specification {
def "try this"(){
when:
def sandbox1 = new SandboxMetaMethod1()
def sandbox2 = new SandboxMetaMethod2()
sandbox1 << sandbox2
then:
true
}
}
//Output
woof
speak
woof
Per Request, I am adding background as to the goal / use case:
It's very much like a standard functional type of use case. In summary, we have a lot of methods on a class which applies to all of our client environments (50-100). We apply those to process data in a certain default order. Each of those methods may be overridden by client specific methods (if they exist with the same method name), and the idea was to use the approach above to "reconcile" the method set. Based on the client environment name, we need a way to dynamically override methods.
Note: Overriding methods on the metaclass is very standard (or should i say, it's the reason the amazing capability exists). And it works if my method exists as text like String currMethod = "{x-> x+1}", then i just say this.metaClass."$currMethodName" = currMethod. My challenge in this case is that my method is compiled and exists on another class, rather than being defined as text somewhere.
The goal of having all the custom methods compiled in client-specific classes at build time was to avoid the expense of compilation of these dynamic methods at runtime for each calculation, so all client-specific methods are compiled into a separate client-specific JAR at build time. This way also allows us to only deploy the client-specific code to the respective client, without all the other clients calculations in some master class.
I hope that makes sense.
New Approach, in Response to Jeremie B's suggestion:
Since I need to choose the trait to implement by name at runtime, will something like this work:
String clientName = "client1"
String clientSpeakTrait = "${clientName}Speak"
trait globalSpeak {
String speak() {
println 'bow wow'
}
}
trait client1Speak {
String speak() {
println 'woof'
}
}
def mySpeaker = new Object().withTraits globalSpeak, clientSpeakTrait
A basic example with Traits :
trait Speak {
String speak() {
println 'bow wow'
}
}
class MyClass {
}
def instance = new MyClass()
def extended = instance.withTraits Speak
extended.speak()
You can choose which trait to use at runtime :
def clientTrait = Speak
def sb = new Object().withTraits(clientTrait)
sb.speak()
And dynamically load the trait with a ClassLoader :
def clientTrait = this.class.classLoader.loadClass "my.package.${client}Speak"
def sb = new Object().withTraits(clientTrait)

Overriding parent methods with contravariant arguments

Basically, I want to override a parent class with different arguments. For example:
class Hold<T> {
public var value:T;
public function new(value:T) {
set(value);
}
public function set(value:T) {
this.value = value;
}
}
Then override that class, something like:
class HoldMore extends Hold<T> {
public var value2:T;
public function new(value:T, value2:T) {
super(value);
set(value, value2);
}
override public function set(value:T, value2:T) {
this.value = value;
this.value2 = value2;
}
}
Obviously this will return an error, Field set overloads parent class with different or incomplete type. Is there a way around this? I tried using a public dynamic function, and then setting set in the new() function, but that gave a very similar error. Any thoughts?
This is just a complement to #stroncium's answer, which is totally correct.
Here is an example how it could look like:
class Hold<T> {
public var value:T;
public function new(value:T) {
set(value);
}
public function set(value:T) {
this.value = value;
}
}
class HoldMore<T> extends Hold<T> {
public var value2:T;
public function new(value:T, value2:T) {
super(value);
setBoth(value, value2);
}
// you cannot override "set" with a different signature
public function setBoth(value:T, value2:T) {
this.value = value;
this.value2 = value2;
}
}
alternatively, you could use an array as parameter or a dynamic object holding multiple values in order to "set" them using the same method, but you loose some of the compiler's type checking.
If you wrote the base class you could add an optional argument to it, this would be a workaround though, not directly what you want to do.
In the current state it totally won't work. There is not only 1 problem, but few of them:
Type T is meaningless in context of this new class, you should either use some concrete type or template this class over T.
You can not change the number of arguments of function when overriding it. However you can add another function(with a different name) to accept 2 arguments and do what you want (which is the way you would use in most languages, by the way).
I don't really understand how you see a contravariance problem there. The actual problem is that haxe doesn't support function overload. (It actually does, the function signature is name + full type, but that's not what you would want to write nor support, and is mostly used for js/java externs.)
Unfortunately the language doesn't allow it.

Possible to register NullObject implementation as a fallback for a generic interface?

We use a lot of Generics in our code. For example ICommandHandler<T> where T is ICommand, ICommandValidator<T> etc etc
Not everything has a ICommandValidator implementation. I was looking to use the NullObject pattern so that I could provide a fall back option to avoid having to test if validator is null.
For example
public class NullObjectCommandValidator : ICommandValidator<ICommand>
{
public bool IsValid(ICommand command)
{
return true;
}
}
We register all like:
builder.RegisterAssemblyTypes(assemblies)
.AsClosedTypesOf(typeof(ICommandValidator<>))
.InstancePerHttpRequest();
I was hoping to be able to register the NullObjectCommandValidator as a default for any ICommandValidator that didn't have a concrete implementation using a process like registering all other ICommandValidators<> and then registering the Null version at the end and preserving existing defaults.
Is something like this possible?
You should change NullObjectCommandValidator to a generic type NullObjectCommandValidator<TCommand>. This way you can register it as follows:
builder.RegisterGeneric(typeof(NullObjectCommandValidator<>))
.As(typeof(ICommandValidator<>));
NullObjectCommandValidator<TCommand> looks like this:
public class NullObjectCommandValidator<TCommand> : ICommandValidator<TCommand>
{
public bool IsValid(TCommand command)
{
return true;
}
}

Resources