javaobjectmethodsclojuretranslate

Converting Java object and method calls to Clojure code


I was specifically trying to test Cjoures's claim that it can work with Java "seamlessly". In general, how do you translate Java code:

object1.object2(some_args).object3.object4(some_other_args).object5.objectnth.method(arg‌​1, arg2, argn);

to Clojure? Some of the objects in the chain maybe static classes, static methods or class variables, some are interfaces. It just doesn't seem straightforward. E.g., the objects in the graphics library. I recall that at one time I tried to create an object (Graphics.) and Clojure said it didn't know that class Graphics.


Solution

  • Lets take a java example:

    public class Test {
    
        public Test a;
    
        public Test getA() {
            return this.a;
        }
    
        public Test add(Test a) {
            this.a = a;
            return this;
        }
    
        public int foo(int a, int b, int c) {
            return a+b+c;
        }
    
        public long foovar(Long... ai) {
            long r = 0;
            for (long i:ai) r+= i;
            return r;
        }
    }
    

    And show a bunch of ways to access internal objects:

    (import 'Test)
    
    ;; create all the objects
    (def t1 (Test.))
    (def t2 (Test.))
    (def t3 (Test.))
    (def t4 (Test.))
    (def t5 (Test.))
    (def t6 (Test.))
    
    ;; and lets chain them together:
    (.add t1 (.add t2 (.add t3 (.add t4 (.add t5 t6)))))
    
    ;; verify using member access:
    (= t6 (.. t1 a a a a a))  ;; true
    
    ;; verify using method call:
    (= t6 (.. t1 getA getA getA getA getA)) ;; true
    
    ;; and mixed access
    (= t6 (.. t1 a a getA a a))  ;; true
    
    ;; lets invoke foo:
    (.. t1 getA getA getA getA getA (foo 1 2 3)) ;; 6
    
    ;; and invoke foovar:
    (.. t1 getA getA getA getA getA (foovar (into-array[1 2 3]))) ;; 6
    

    Now we can also create helper functions:

    ;; get the object at depth n using functions
    (defn get-nth-function [o n]
      (first (drop n (iterate (memfn getA) o))))
    
    ;; get the object at depth n using member access.
    ;; This same notation could also be used for function,
    ;; however I just wanted to show an example of memfn
    (defn get-nth-member [o n]
      (first (drop n (iterate #(.a %) o))))
    
    ;; lets verify:
    (= t6 (get-nth-member t1 5)) ;; true
    
    ;; lets invoke foovar on object position 6, 
    ;; on a range of numbers from 1 to 10
    (.foovar (get-nth t1 5) (into-array (range 10))) ;; 45
    

    This should shows the flexibility of interacting between clojure and java. When you have static members, you could access them with / as you did for System/out (although . works too). Please be sure to fully read http://clojure-doc.org/articles/language/interop.html and if you still dont get something, let us know.