I'm writing a Gradle plugin in Scala.
To allow me to configure the plugin and associated tasks via a Gradle DSL I need to be able to invoke methods dynamically (i.e. methods that don't actually exist). If I were writing the plugin in Groovy I'd use methodMissing or propertyMissing as described here.
In Scala I can invoke functions dynamically using dynamic member lookup. This works when invoking the functions from Scala code but I can't seem to find a way to invoke these dynamic functions from Groovy (i.e. when the Scala plugin is used as part of another Gradle project).
Is it possible to utilise Scala's dynamic member lookup from Groovy? Or is this a dead end?
Just figured out the answer to my question. In Scala I need to implement the same methodMissing and propertyMissing functions that I'd implement if I were writing a Groovy class and have the Scala class extend GroovyObjectSupport (needed for Gradle integration).
If anyone else is trying to do something similar below are the function signatures in Scala you need to implement:
class Foo extends GroovyObjectSupport {
def methodMissing(m: String, arg: Any): Any = ???
def propertyMissing(p: String): Any = ???
def propertyMissing(p: String, v: Any): Any = ???
}
Related
In developing a Groovy library to be used with Java code, I want to be able to use Java Lambdas than Groovy specific mechanisms.
When accessing this library API from the Java side the user should not need any Groovy specific imports or expose any Groovy specifics features.
Java-specific Lambdas could be pass to the API and also Java-specific Lambdas should be returned from the API.
Is there a way that this can be achieved?
E.g.
def f() {
return { n -> n + 1}
}
The return type of f is groovy.lang.Closure. I want it to be Function.
Also, instead of
def f(Closure c) {
...
c.delegate = this
c.resolveStrategy = DELEGATE_ONLY
...
}
I want to replace Closure c with Function.
In doing so when using it from the Java side Groovy features and API are not exposed to the developer.
The short answer is that you will be able to do this just like in Java.
In java a lamda is accepted as an object that implements a functional interface - a functional interface being an interface that contains only a single abstract method which matches the signature of the lambda you will pass in.
As an example, you can use the Runnable interface which has just a run method with no parameters.
In groovy you will accept an object of type Runnable:
def myGroovyFunction(Runnable r) {
r.run()
}
You can use any functional interface here, for example something from java.util.function or your own interface.
your java code can now pass in a lambda like so:
MyGroovyClass.myGroovyFunction(() -> {
System.out.println("This will be printed by the groovy function");
})
I have a spark Scala library and I am building a python wrapper on top of it. One class of my library provides the following method
package com.example
class F {
def transform(df: DataFrame): DataFrame
}
and I am using py4j in the following way to create a wrapper for F
def F():
return SparkContext.getOrCreate()._jvm.com.example.F()
which allows me to call the method transform
The problem is that the python Dataframe object is obviously different from the Java Dataframe object. For this purpose, I need a way to convert a python df to a java one, for which I use the following code from py4j docs
class DataframeConverter(object):
def can_convert(self, object):
from pyspark.sql.dataframe import DataFrame
return isinstance(object, DataFrame)
def convert(self, object, gateway_client):
from pyspark.ml.common import _py2java
return _py2java(SparkContext.getOrCreate(), object)
protocol.register_input_converter(DataframeConverter())
My problem is that now I want to do the inverse: getting a java dataframe from the transform and continue to use it in python. I tried to use protocol.register_output_converter but I couldn't find any useful example, apart for code dealing with java collections.
How can I do that? An obvious solution would be to create a python class F which defines all methods present in java F, forwards all the python calls to the jvm, get back the result and convert it accordingly. This approach works but it implies that I have to redefine all methods of F thus generating code duplication and a lot more maintainance
Similar to dynamic SQL, wherein a String is executed as an SQL at runtime, can we have Java code run dynamically? Like I return a String which is a Java code and then I execute at runtime. Is this possible?
For real Java code, this is possible using the JavaCompiler interface. However, it's very inconvenient to use since it's just an interface to a real Java compiler that expects to compile entire class definitions found in files.
The easiest way to execute code supplied at runtime would be to use the Rhino JavaScript engine.
Both of these options have been only in Java 6, though I believe the scripting interface existed before, so you could use Rhino in an earlier JRE if you download and add it to the classpath.
Javassist
You would need to use a bytecode manipulation library such as Javassist (Wikipedia), in order to run an arbitrary string that is provided at runtime. Javassist allows you to create a CtClass based on a string representing source code; and can then turn this into compiled Class object via a particular classloader, so that the class is then available to your application. Other libraries would need to do something similar to these two steps in order to achieve the same thing.
So it is possible, but it's very heavyweight and is likely to make your application very hard to reason about. If at all possible, consider designing a very flexible class statically, and having it accept parameters that control its behaviour.
If you want to do more than invoke an existing method dynamically, you may need to compile your String into bytecode. An easy way to do this is to include the Eclipse/JDT compiler jar in your classpath, and then you can use that to compile your String into a Class, which can then be loaded.
This type of dynamic code generation and execution is used to convert JSP files into Servlets and is used in other packages such as JasperReports to turn a report specification into a Class that is then invoked.
Remember that just as with SQL you must be careful to prevent code injection security problems if any of the String contains user-specified data.
You also may want to look at Java 6 scripting support:
http://download.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.htm
Here is a version of hello world that creates array of strings and prints a first one:
import javax.script.*;
public class EvalScript {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
engine.eval("var a=java.lang.reflect.Array.newInstance(java.lang.String, 1);a[0]='Hello World';print(a[0])");
}
}
Yes it is possible. Look at the Java Compiler API. Have a look here:
http://download.oracle.com/javase/6/docs/api/javax/tools/JavaCompiler.html
Have a look at Beanshell. It provides an interpreter with java like syntax.
I'm trying to figure out the difference between
Groovy:
def name = "stephanie"
Java:
Object name = "stephanie"
as both seem to act as objects in that to interact with them i have to cast them to their original intended type.
I was originally on a search for a java equivalent of C#'s dynamic class ( Java equivalent to C# dynamic class type? ) and it was suggested to look at Groovy's def
for example my impression of groovy's def is that I could do the following:
def DOB = new Date(1998,5,23);
int x = DOB.getYear();
however this wont build
thanks,steph
Solution edit:
Turns out the mistake iw as making is I had a groovy class wtih public properties (in my example above DOB) defined with def but then was attemping to access them from a .java class(in my example above calling .getYear() on it). Its a rookie mistake but the problem is once the object leaves a Groovy file it is simply treated as a Object. Thanks for all your help!
Per se, there is not much difference between those two statements; but since Groovy is a dynamic language, you can write
def name = "Stephanie"
println name.toUpperCase() // no cast required
while you would need an explicit cast in the Java version
Object name = "Stephanie";
System.out.println(((String) name).toUpperCase());
For that reason, def makes much more sense in Groovy than unfounded use of Object in Java.
You can experiment with groovy in the groovy web console http://groovyconsole.appspot.com/
Your initial groovy date example works.
Similar to dynamic SQL, wherein a String is executed as an SQL at runtime, can we have Java code run dynamically? Like I return a String which is a Java code and then I execute at runtime. Is this possible?
For real Java code, this is possible using the JavaCompiler interface. However, it's very inconvenient to use since it's just an interface to a real Java compiler that expects to compile entire class definitions found in files.
The easiest way to execute code supplied at runtime would be to use the Rhino JavaScript engine.
Both of these options have been only in Java 6, though I believe the scripting interface existed before, so you could use Rhino in an earlier JRE if you download and add it to the classpath.
Javassist
You would need to use a bytecode manipulation library such as Javassist (Wikipedia), in order to run an arbitrary string that is provided at runtime. Javassist allows you to create a CtClass based on a string representing source code; and can then turn this into compiled Class object via a particular classloader, so that the class is then available to your application. Other libraries would need to do something similar to these two steps in order to achieve the same thing.
So it is possible, but it's very heavyweight and is likely to make your application very hard to reason about. If at all possible, consider designing a very flexible class statically, and having it accept parameters that control its behaviour.
If you want to do more than invoke an existing method dynamically, you may need to compile your String into bytecode. An easy way to do this is to include the Eclipse/JDT compiler jar in your classpath, and then you can use that to compile your String into a Class, which can then be loaded.
This type of dynamic code generation and execution is used to convert JSP files into Servlets and is used in other packages such as JasperReports to turn a report specification into a Class that is then invoked.
Remember that just as with SQL you must be careful to prevent code injection security problems if any of the String contains user-specified data.
You also may want to look at Java 6 scripting support:
http://download.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.htm
Here is a version of hello world that creates array of strings and prints a first one:
import javax.script.*;
public class EvalScript {
public static void main(String[] args) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
engine.eval("var a=java.lang.reflect.Array.newInstance(java.lang.String, 1);a[0]='Hello World';print(a[0])");
}
}
Yes it is possible. Look at the Java Compiler API. Have a look here:
http://download.oracle.com/javase/6/docs/api/javax/tools/JavaCompiler.html
Have a look at Beanshell. It provides an interpreter with java like syntax.