Calling a very simple clojure function from Java does not work - java

I'm very new in learning Clojure. This intended to be my first and very simple Clojure tries in which I call a simple Clojure method from inside java code. Unfortunately it does not work. The Compilation is successful and from the Clojure REPL the written function does as it was ordered, but when calling from Java it says the following:
Exception in thread "main" java.lang.IllegalArgumentException: Wrong number of args (2) passed to: ClojNum$-myinc
at clojure.lang.AFn.throwArity(AFn.java:439)
at clojure.lang.AFn.invoke(AFn.java:43)
at com.experimental.clojure.test.ClojNum.myinc(Unknown Source)
at com.experimental.clojure.java.JavaCaller.main(JavaCaller.java:14)
Here is the very simple Clojure code:
(ns com.experimental.clojure.test.ClojNum
(:gen-class
:init init
:name com.experimental.clojure.test.ClojNum
:methods [
[myinc [int] int]
]))
(defn -init [] [[] (atom [])])
(defn myinc "comment" [x] (+ x 1))
(defn -myinc "comment" [x] (myinc x))
And the java part:
package com.experimental.clojure.java;
import com.experimental.clojure.test.ClojNum;
public class JavaCaller {
/**
* #param args
*/
public static void main(String[] args) {
int i = 0;
System.out.println(i);
ClojNum c = new ClojNum();
i = c.myinc(0);
System.out.println(i);
}
}
What did I do wrong?
(Note again: This is primitve test code just to make a first successful function call)
Thanks for the help, I'm clueless.

Jeremy's link in the comments show you one way to call a static method in a clojure class. If you want to call a clojure function on an object instance, you need to add a parameter to your wrapper method definition:
(defn -myinc "comment" [this x] (myinc x))
The 'this' parameter is required for any non-static wrapper function. Clojure threw an exception because it received two parameters for a function only defined with one. Note, you do not change anything in your :gen-class :methods section or the myinc function definition itself.
The documentation is a bit sparse, but examples of this can be found at:
http://clojure.org/compilation (the last example on the page shows instance methods).

Related

Clojure gen-class this keyword

Is it possible to refer to Java's 'this' keyword from within a gen-class method?
I am trying to implement daredesm's answer here, in Clojure. However, when I try to use 'this' in the run function, I get "java.lang.RuntimeException: Unable to resolve symbol: this in this context."
(gen-class
:name ClipboardListener
:extends java.lang.Thread
:implements [java.awt.datatransfer.ClipboardOwner]
:prefix ClipboardListener-
:methods [[takeOwnership [Transferable] void]])
(def systemClipboard (.getSystemClipboard (java.awt.Toolkit/getDefaultToolkit)))
(defn ClipboardListener-run []
(let [transferable (.getContents systemClipboard this)]
(.takeOwnership transferable)))
(defn ClipboardListener-lostOwnership [clipboard trasferable] (prn "hit lost"))
(defn ClipboardListener-takeOwnership [transferable] (prn "hit take"))
(defn processClipboard [transferable clipboard] (prn "hit process"))
Note: This is my first time generating Java classes in Clojure, so any general feedback/resources is greatly appreciated.
Instance methods can take an implicit 'self' arg- as the first argument. So to take your example:
(defn ClipboardListener-run [this]
(let [transferable (.getContents systemClipboard this)]
(.takeOwnership transferable)))
Note the this argument :)
Same goes for any instance method, e.g:
(defn ClipboardListener-toString [this]
"override Object#toString with something cool")
Have a look at this (no pun intended) for more info on gen-class.
Also consider reify for cases like Runnable, Callable, e.t.c where you just need to implement a small-ish interface.

proxy cant implement java.lang.Thread

im trying to implement this in java
window.addWindowListener(new WindowAdapter() {
#Override
public void windowDestroyNotify(WindowEvent arg0){
new Thread(){
#Override
public void run(){
animator.stop();
System.exit(0);
}
}.start();
};
});
as this in clojure
(.addWindowListener (proxy [WindowAdapter][]
(windowDestroyNotify [arg0]
(.start (proxy [java.lang.Thread][]
(run
(.stop ani)
(System/exit 0)))))))
but when i run it, it gives me this error
CompilerException java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol, compiling: (program/core.clj:36:36)
36:36 is where "(proxy [java.lang.Thread]" starts
why can't it implement java.lang.Thread
The exception is misleading, but the problem is in the implementation of the run method in the proxy Thread, it is missing the arguments vector.
The following expression when compiled generates the same exception:
(proxy [Thread] [] (run (inc 1)))
While this one doesn't:
(proxy [Thread] [] (run [] (inc 1)))
The misleading error is because of how the proxy macro parses its arguments.
Start over and build it up slowly from small pieces:
(let [t (Thread. #(println "going 1")) ]
(.start t))
;=> going 1
(let [t (proxy [Thread] []
(run [] (println "going 2")))
]
(.start t))
;=> going 2
So you can see the problem is not proxy or Thread but in your surrounding code.
Update
Juan noticed the problem first as the missing arglist [] for run. By reading the docs at https://clojuredocs.org/clojure.core/proxy and building up the sample slowely, I got the arglist in the sample code automatically.
I have found that understanding a problem by "synthesis" allows you to bypass many problems. It is often much faster & easier than trying to understand a problem by "analysis", where you start with the finished product and then try to figure out what caused it to go wrong.

Log all method calls to a Java object from Clojure

I'm working on a Clojure wrapper for some Java library.
In order to help me debug, I would like to log all calls to specific Java objects.
After searching how I might do this from a raw Java perspective, I discovered the java.lang.reflect.Proxy class and java.lang.reflect.InvocationHandler interfaces.
This led me to find a small snipped posted by R.H. a few years ago :
(defn debug-proxy [obj]
(java.lang.reflect.Proxy/newProxyInstance
(.. obj getClass getClassLoader)
(.. obj getClass getInterfaces)
(proxy [java.lang.reflect.InvocationHandler] []
(invoke [proxy m args]
(apply println m args)
(.invoke m obj args)))))
Small note: I had to change java.lang.reflect.Proxy.newProxyInstance into java.lang.reflect/newProxyInstance to make it work in my REPL, since newProxyInstance is a static method. Corrected version is given so that you may cut & paste it.
With this version, calling methods on the proxy appear work at first :
youpi.core=> (.charAt (debug-proxy "foo") 2)
#object[java.lang.reflect.Method 0x53ce1eb0 public abstract char java.lang.CharSequence.charAt(int)] 2
=> \o
But sadly, calling a method that accepts no argument will not work:
youpi.core=> (.toUpperCase (debug-proxy "foo"))
IllegalArgumentException No matching field found: toUpperCase for class com.sun.proxy.$Proxy1 clojure.lang.Reflector.getInstanceField (Reflector.java:271)
java.lang.IllegalArgumentException: No matching field found: toUpperCase for class com.sun.proxy.$Proxy1
at clojure.lang.Reflector.getInstanceField(Reflector.java:271)
at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:315)
at youpi.core$eval5981.invokeStatic(form-init3685547971046661105.clj:1)
at youpi.core$eval5981.invoke(form-init3685547971046661105.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6927)
at clojure.lang.Compiler.eval(Compiler.java:6890)
at clojure.core$eval.invokeStatic(core.clj:3105)
at clojure.core$eval.invoke(core.clj:3101)
at clojure.main$repl$read_eval_print__7408$fn__7411.invoke(main.clj:240)
at clojure.main$repl$read_eval_print__7408.invoke(main.clj:240)
<...>
at java.lang.Thread.run(Thread.java:745)
I tried to update the invoke implementation following advice given in this clojuredocs comment, but it didn't fix.
Here is my (still broken) attempt at implementing the comment's suggestion:
(defn- debug-print-invoke [obj proxy m args]
(apply println m args)
(.invoke m obj args))
(defn debug-proxy [obj]
(java.lang.reflect.Proxy/newProxyInstance
(.. obj getClass getClassLoader)
(.. obj getClass getInterfaces)
(proxy [java.lang.reflect.InvocationHandler] []
(invoke
([proxy m] (debug-print-invoke obj proxy m []))
([proxy m args] (debug-print-invoke obj proxy m args))))))
A good answer would either fix the snippet I've been working with, or suggest an alternative way to achieve the same goal from Clojure.

How to call String[][] in R using rjava

I am preparing an R wrapper for a java code that I didn't write myself (and in fact I don't know java). I am trying to use rJava for the first time and I am struggling to get the .jcall right.
Here is an extract of the java code for which I write a wrapper:
public class Model4R{
[...cut...]
public String[][] runModel(String dir, String initFileName, String[] variableNames, int numSims) throws Exception {
[...cut...]
dir and initFileName are character strings for the directory and file name with initial conditions, variable names is a list of character strings that I would write like this in R: c("var1", "var2", "var3", ...) and can be of length from one to five. Finally, numSim is an integer.
Here is my tentative R code for a wrapper function:
runmodel <- function(dir, inFile, varNames, numSim){
hjw <- .jnew("Model4R")
out <- .jcall(hjw, "[[Ljava/lang/String", "runModel", as.character(dir), as.character(inFile), as.vector(varNames), as.integer(numSim))
return(out)
}
The error in R is:
Error in .jcall(hjw, "[[Ljava/lang/String", "runModel", as.character(dir),
: method runModel with signature (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;II)[[Ljava/lang/String not found
I suspect that the JNI type isn't correct for String[][]. Anyhow, any help that could direct me towards a solution would be welcome!
You're missing a semicolon at the end of the JNI for String[][] - it should be "[[Ljava/lang/String;". Also, I think you need to call .jarray instead of as.vector on varNames. The R error is telling you that rJava thinks the class of the third argument is Ljava/lang/String; instead of [Ljava/lang/String;.

Clojure macro for calling Java setters based on a map?

I'm writing a Clojure wrapper for the Braintree Java library to provide a more concise and idiomatic interface. I'd like to provide functions to instantiate the Java objects quickly and concisely, like:
(transaction-request :amount 10.00 :order-id "user42")
I know I can do this explicitly, as shown in this question:
(defn transaction-request [& {:keys [amount order-id]}]
(doto (TransactionRequest.)
(.amount amount)
(.orderId order-id)))
But this is repetitive for many classes and becomes more complex when parameters are optional. Using reflection, it's possible to define these functions much more concisely:
(defn set-obj-from-map [obj m]
(doseq [[k v] m]
(clojure.lang.Reflector/invokeInstanceMethod
obj (name k) (into-array Object [v])))
obj)
(defn transaction-request [& {:as m}]
(set-obj-from-map (TransactionRequest.) m))
(defn transaction-options-request [tr & {:as m}]
(set-obj-from-map (TransactionOptionsRequest. tr) m))
Obviously, I'd like to avoid reflection if at all possible. I tried defining a macro version of set-obj-from-map but my macro-fu isn't strong enough. It probably requires eval as explained here.
Is there a way to call a Java method specified at runtime, without using reflection?
Thanks in advance!
Updated solution:
Following the advice from Joost, I was able to solve the problem using a similar technique. A macro uses reflection at compile-time to identify which setter methods the class has and then spits out forms to check for the param in a map and call the method with it's value.
Here's the macro and an example use:
; Find only setter methods that we care about
(defn find-methods [class-sym]
(let [cls (eval class-sym)
methods (.getMethods cls)
to-sym #(symbol (.getName %))
setter? #(and (= cls (.getReturnType %))
(= 1 (count (.getParameterTypes %))))]
(map to-sym (filter setter? methods))))
; Convert a Java camelCase method name into a Clojure :key-word
(defn meth-to-kw [method-sym]
(-> (str method-sym)
(str/replace #"([A-Z])"
#(str "-" (.toLowerCase (second %))))
(keyword)))
; Returns a function taking an instance of klass and a map of params
(defmacro builder [klass]
(let [obj (gensym "obj-")
m (gensym "map-")
methods (find-methods klass)]
`(fn [~obj ~m]
~#(map (fn [meth]
`(if-let [v# (get ~m ~(meth-to-kw meth))] (. ~obj ~meth v#)))
methods)
~obj)))
; Example usage
(defn transaction-request [& {:as params}]
(-> (TransactionRequest.)
((builder TransactionRequest) params)
; some further use of the object
))
You can use reflection at compile time ~ as long as you know the class you're dealing with by then ~ to figure out the field names, and generate "static" setters from that. I wrote some code that does pretty much this for getters a while ago that you might find interesting. See https://github.com/joodie/clj-java-fields (especially, the def-fields macro in https://github.com/joodie/clj-java-fields/blob/master/src/nl/zeekat/java/fields.clj).
The macro could be as simple as:
(defmacro set-obj-map [a & r] `(doto (~a) ~#(partition 2 r)))
But this would make your code look like:
(set-obj-map TransactionRequest. .amount 10.00 .orderId "user42")
Which I guess is not what you would prefer :)

Categories

Resources