How do I use a Java-defined instance method in Lua? - java

I'm aware that it is possible to use Java defined static methods in Lua, due to the section "Libraries of Java Functions" on http://luaj.org/luaj/README.html.
However I am struggling to find out how I can use the same for instance methods, I have a shortened example here:
private static class CallbackStore {
public void test(final String test) {
}
}
(I am aware that I can use a static method here as well, but it is not possible with the real life scenario)
I am using the following Lua code:
-- Always name this function "initCallbacks"
function initCallbacks(callbackStore)
callbackStore.test("test")
end
Which does not work as it is expecting userdata back, but I give it a string.
And I call the Lua code like this:
globals.load(new StringReader(codeTextArea.getText()), "interopTest").call();
CallbackStore callbackStore = new CallbackStore();
LuaValue initCallbacks = globals.get("initCallbacks");
initCallbacks.invoke(CoerceJavaToLua.coerce(callbackStore));
where the Lua code is returned by codeTextArea.getText()
Bottom line of my question is, how do I make my code running with test as an instance method?

When accessing member functions (in Lua objects in general, not just luaj) you have to provide the this argument manually as the first argument like so:
callbackStore.test(callbackStore,"test")
Or, you can use the shorthand notation for the same thing:
callbackStore:test("test")

Related

nameof equivalent in Java

C# 6.0 introduced the nameof() operator, that returns a string representing the name of any class / function / method / local-variable / property identifier put inside it.
If I have a class like this:
class MyClass
{
public SomeOtherClass MyProperty { get; set; }
public void MyMethod()
{
var aLocalVariable = 12;
}
}
I can use the operator like this:
// with class name:
var s = nameof(MyClass); // s == "MyClass"
// with properties:
var s = nameof(MyClass.OneProperty); // s == "OneProperty"
// with methods:
var s = nameof(MyClass.MyMethod); // s == "MyMethod"
// with local variables:
var s = nameof(aLocalVariable); // s == "aLocalVariable".
This is useful since the correct string is checked at compile time. If I misspell the name of some property/method/variable, the compiler returns an error. Also, if I refactor, all the strings are automatically updated. See for example this documentation for real use cases.
Is there any equivalent of that operator in Java? Otherwise, how can I achieve the same result (or similar)?
It can be done using runtime byte code instrumentation, for instance using Byte Buddy library.
See this library: https://github.com/strangeway-org/nameof
The approach is described here: http://in.relation.to/2016/04/14/emulating-property-literals-with-java-8-method-references/
Usage example:
public class NameOfTest {
#Test
public void direct() {
assertEquals("name", $$(Person.class, Person::getName));
}
#Test
public void properties() {
assertEquals("summary", Person.$(Person::getSummary));
}
}
Sadly, there is nothing like this. I had been looking for this functionality a while back and the answer seemed to be that generally speaking, this stuff does not exist.
See Get name of a field
You could, of course, annotate your field with a "Named" annotation to essentially accomplish this goal for your own classes. There's a large variety of frameworks that depend upon similar concepts, actually. Even so, this isn't automatic.
You can't.
You can get a Method or Field using reflection, but you'd have to hardcode the method name as a String, which eliminates the whole purpose.
The concept of properties is not built into java like it is in C#. Getters and setters are just regular methods. You cannot even reference a method as easily as you do in your question. You could try around with reflection to get a handle to a getter method and then cut off the get to get the name of the "property" it resembles, but that's ugly and not the same.
As for local variables, it's not possible at all.
You can't.
If you compile with debug symbols then the .class file will contain a table of variable names (which is how debuggers map variables back to your source code), but there's no guarantee this will be there and it's not exposed in the runtime.
I was also annoyed that there is nothing comparable in Java, so I implemented it myself: https://github.com/mobiuscode-de/nameof
You can simply use it like this:
Name.of(MyClass.class, MyClass::getProperty)
which would just return the String
"property"
It's also on , so you can add it to your project like this:
<dependency>
<groupId>de.mobiuscode.nameof</groupId>
<artifactId>nameof</artifactId>
<version>1.0</version>
</dependency>
or for Gradle:
implementation 'de.mobiuscode.nameof:nameof:1.0'
I realize that it is quite similar to the library from strangeway, but I thought it might be better not to introduce the strange $/$$ notation and enhanced byte code engineering. My library just uses a proxy class on which the getter is called on to determine the name of the passed method. This allows to simply extract the property name.
I also created a blog post about the library with more details.
Lombok has an experimental feature #FieldNameConstants
After adding annotation you get inner type Fields with field names.
#FieldNameConstants
class MyClass {
String myProperty;
}
...
String s = MyClass.Fields.myProperty; // s == "myProperty"

How can I call a method defined on a Scala package object from Java? (Scala 2.10.x)

Given a method defined on a (3rd party, so I can't just move it) Scala package object, like so:
package foo
package object bar {
def doSomething(s: String): String = ???
}
I need to call doSomething from Java code. I know that in general, I can get at a Scala companion object's methods from Java using ScalaObject$.method(). However, the example above compiles to foo.bar.package$.class, and of course Java screams about package being a reserved word.
Is there a way to call this from Java directly?
The best I can come up with (works, but ugly) is to wrap doSomething in Scala code that's not in a package object, and then call the wrapper from my Java code.
object BarUtil {
def wrapper(s: String) = foo.bar.doSomething(s)
}
and in Java
public String doIt(String s) {
return BarUtil$.wrapper(s);
}
You can access the package object as foo.bar.package$.MODULE$ (note the dollar signs, do not remove them):
foo.bar.package$.MODULE$.doSomething("hello")

Is it possible to use a Java 8 style method references in Scala?

I'm developing a JavaFX8 application in Scala but I couldn't figure out how to pass a method reference to an event handler. To clarify, I'm not using ScalaFX library but build my application directly on top of JavaFX.
Here's the related code snippet.
InputController.java (I wrote this test class in Java to isolate the issue to consume a method reference only)
public class InputController {
public void handleFileSelection(ActionEvent actionEvent){
//event handling code
}
public InputController() {
//init controller
}
}
This works (Java)
InputController inputController = new InputController();
fileButton.setOnAction(inputController::handleFileSelection);
This doesn't work (Scala)
val inputController = new InputController
fileButton.setOnAction(inputController::handleFileSelection)
Here's the error message from the compiler (Scala 2.11.6).
Error:(125, 45) missing arguments for method handleFileSelection in class Main;
follow this method with '_' if you want to treat it as a partially applied function
fileButton.setOnAction(inputController::handleFileSelection)
^
If I use Scala 2.12.0-M2 instead, I get a different error message.
Error:(125, 45) missing argument list for method handleFileSelection in class Main
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `handleFileSelection _` or `handleFileSelection(_)` instead of `handleFileSelection`.
fileButton.setOnAction(inputController::handleFileSelection)
^
Is there a native way which Scala can leverage method references introduced in Java 8? I'm aware of the implicit conversions approach to use a lambda expression but I want to know if there is a way to use a method reference similar to Java 8 without needing to use the lambda decleration.
inputController::handleFileSelection is Java syntax, which isn't supported or needed in Scala because it already had a short syntax for lambdas like this: inputController.handleFileSelection _ or inputController.handleFileSelection(_) (inputController.handleFileSelection can also work, depending on the context).
However, in Java you can use lambdas and method references when any SAM (single abstract method) interface is expected, and EventHandler is just such an interface. In Scala before version 2.11 this isn't allowed at all, in 2.11 there is experimental support for using lambdas with SAM interfaces, which has to be enabled using -Xexperimental scalac flag, and starting from 2.12 it is fully supported and doesn't need to be enabled.
You should pass function which applying one parameter of type ActionEvent:
val button = new Button()
val inputController = new InputController()
def handler(h: (ActionEvent => Unit)): EventHandler[ActionEvent] =
new EventHandler[ActionEvent] {
override def handle(event: ActionEvent): Unit = h(event)
}
button.setOnAction(handler(inputController.handleFileSelection))
If you want a method reference that also takes the class instance as a parameter, for instance like String::length in Java, you can do (_:String).length which is equivalent to (s:String) => s.length().
The types of these are in Java Function<String, Integer> and in Scala thus String => Int.
Could you try
fileButton.setOnAction(() => inputController.handleFileSelection())

Get the name of the functions called by a class

There are two classes A and B in the same package.
how to get name of the functions of class A called by class B.
Restriction is that the code of A and B cannot be modified.
You cannot use Java reflection to do static code analysis tasks like this. The reflection APIs don't provide the information that is needed.
Off the top of my head, I can think of two approaches that will work:
If you only have the ".class" files, then you can use a bytecode library such as BCEL to load the classes and traverse them to identify all of the method calls.
If you have source code, you could also use some existing Java parser library to create ASTs for your code and analyse them.
(The first approach is probably simpler if all you want is a list of class and method names.)
Reflection can be very useful, but very complicated if you don't understand it.
If you have the name of the class, and want to print the methods:
Class c = Class.forName(the_class_name);
for(Method m : c.getMethods()) {
System.out.println(m.toString());
}
If you want the name of a class given any Object:
String className = the_object.getClass().getName();
A combination of the two could look like this:
for(Method m : the_object.getClass().getMethods())
System.out.println(m.toString());
I think what you are asking for is the names of all the methods from A that B calls.
That can't really be done with reflection, mostly because Java doesn't provide any method for doing this.
The API, as always, provides more information. If you look through there, you might come up with a simple work around.
"Class of all the functions called by class A or class B" is confusing. But, If You want to get the class and function name of caller to a method detectsName described in your class A , then following code will be useful to you.
public class A {
public void detectsName() {
Throwable t = new Throwable();
StackTraceElement traceLine = t.getStackTrace()[1];
// t.printStackTrace();
String className = traceLine.getClassName();
String methodName = traceLine.getMethodName();
int lineNumber = traceLine.getLineNumber();
System.out.println(className);
System.out.println(methodName);
System.out.println(lineNumber);
}
}
If you call this method from any other class say - B, it will be detected.
public class B {
public static void main(String[] args) {
A a = new A();
a.detectsName();
}
}
Dependency Finder can do queries for this. Its approach is to generate meta data in XML and then use regexp based comparison. You may be specifically looking for feature called 'closure' with inbound reference..

JRuby calls the wrong method

I got a strange problem with a call to a Java method from JRuby.
In my Java class these methods are defined twice, and it appears JRuby calls the wrong one.
So I tried to use java_method, but I always got a:
TypeError: cannot convert instance of class org.jruby.RubyModule to class java.lang.Class
Here's my Java code:
public class Renderer {
...
public void addRenderer(IElementRenderer r) {
System.out.println("Added element render: " + r.getClass().toString());
basicRenderers.add(r);
rendererMap.put(r.elementClass(), r);
}
public void addRenderer(IBasicRenderer r) {
System.out.println("SHOULD NOT GO THERE !!");
basicRenderers.add(r);
}
}
and my JRuby code:
add_renderer = renderer.java_method :add_renderer, [Java::dragon.render.IElementRenderer]
add_renderer.call TextRenderer.new
I also tried with java_send but I got the same error:
renderer.java_send(:add_renderer, [Java::dragon.render.IElementRenderer], TextRenderer.new)
Next, I tried with:
renderer.add_renderer(TextRenderer.new.to_java(IElementRenderer))
This time no errors but the wrong method is called ...
How can I fix this problem?
You can fix that cannot convert instance of class org.jruby.RubyModule to class java.lang.Class using java.lang.Class.for_name
In your case, it is
add_renderer = renderer.java_method :add_renderer, [java.lang.Class.for_name("dragon.render.IElementRenderer")]
This is because java interfaces become Ruby Modules by default and the second argument to :java_method expects an array of Class objects.
You can print the matched method to see it is matching the intended method.
For example, I see below code is matching the println(String) on System.out.
>>java.lang.System.out.java_method "println", [java.lang.Class.for_name("java.lang.String")]
#<Method: Java::JavaIo::PrintStream#(java.lang.String)>
I've had problems like this before. It was many versions ago and I think JRuby's method matching algorithm has improvedd over time. Are you using the latest JRuby?
If nothing else works, you may need to add another method, or a wrapper class. Something that distinguishes your methods by name or number of parameters, not just parameter type.

Categories

Resources