2

I am working on an Android app which makes use of Clojure for carrying out some of the computation in the backend. However, I am unable to figure out a way to invoke my Clojure methods in Android.

My Clojure program looks like the following:

foobar.MAST (MAST.clj):

(ns foobar.MAST
  (:gen-class
    :name foobar.MAST
    :methods [#^{:static true} [evaluate [String] String]]))

(defn -evaluate [input]
  ...)
(defn -main [& args]
  ...)

project.clj:

(defproject foobar "0.1.0-SNAPSHOT"
  :description "foobar"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :repl-options {:init-ns foobar.core}
  :target-pat "target/%s"
  :profiles {:uberjar {:aot :all}}
  :java-source-paths ["foobar"]
  :main foobar.MAST)

I tried building the project with lein uberjar, then adding the standalone jar in my Android Studio project structure. This allowed me to invoke MAST.evaluate(String) when running a simple kotlin script, but when trying to run it in an Android app, it results in the following runtime error message.

E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.cass, PID: 2404
    java.lang.ExceptionInInitializerError
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:97)
        at clojure.core$fn__8493.invokeStatic(core.clj:7060)
        at clojure.core$fn__8493.invoke(core.clj:7055)
        at clojure.core__init.load(Unknown Source:7055)
        at clojure.core__init.<clinit>(Unknown Source:94)
        at java.lang.Class.classForName(Native Method)
        at java.lang.Class.forName(Class.java:454)
        at clojure.lang.RT.classForName(RT.java:2211)
        at clojure.lang.RT.classForName(RT.java:2220)
        at clojure.lang.RT.loadClassForName(RT.java:2239)
        at clojure.lang.RT.load(RT.java:449)
        at clojure.lang.RT.load(RT.java:424)
        at clojure.lang.RT.<clinit>(RT.java:338)
        at clojure.lang.Namespace.<init>(Namespace.java:34)
        at clojure.lang.Namespace.findOrCreate(Namespace.java:176)
        at clojure.lang.Var.internPrivate(Var.java:156)
        at foobar.MAST.<clinit>(Unknown Source:4)
        at foobar.MAST.evaluate(Unknown Source:0)
        at com.example.cass.model.comp.TexLisp.evaluate(Texlisp.kt:22)
        at com.example.cass.ui.solution.solution_graph.SolutionStepActivity$bindNonMutatingOperations$1.onClick(SolutionStepActivity.kt:55)
        at android.view.View.performClick(View.java:7870)
        at android.view.View.performClickInternal(View.java:7839)
        at android.view.View.access$3600(View.java:886)
        at android.view.View$PerformClick.run(View.java:29363)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:237)
        at android.app.ActivityThread.main(ActivityThread.java:7948)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075)
     Caused by: java.lang.NoSuchMethodException: canAccess [class java.lang.Object]
        at java.lang.invoke.MethodHandles$Lookup.findVirtual(MethodHandles.java:923)
        at clojure.lang.Reflector.<clinit>(Reflector.java:38)
        at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:97) 
        at clojure.core$fn__8493.invokeStatic(core.clj:7060) 
        at clojure.core$fn__8493.invoke(core.clj:7055) 
        at clojure.core__init.load(Unknown Source:7055) 
        at clojure.core__init.<clinit>(Unknown Source:94) 
        at java.lang.Class.classForName(Native Method) 
        at java.lang.Class.forName(Class.java:454) 
        at clojure.lang.RT.classForName(RT.java:2211) 
        at clojure.lang.RT.classForName(RT.java:2220) 
        at clojure.lang.RT.loadClassForName(RT.java:2239) 
        at clojure.lang.RT.load(RT.java:449) 
        at clojure.lang.RT.load(RT.java:424) 
        at clojure.lang.RT.<clinit>(RT.java:338) 
        at clojure.lang.Namespace.<init>(Namespace.java:34) 
        at clojure.lang.Namespace.findOrCreate(Namespace.java:176) 
        at clojure.lang.Var.internPrivate(Var.java:156) 
        at foobar.MAST.<clinit>(Unknown Source:4) 
        at foobar.MAST.evaluate(Unknown Source:0) 
        at com.example.cass.model.comp.TexLisp.evaluate(Texlisp.kt:22) 
        at com.example.cass.ui.solution.solution_graph.SolutionStepActivity$bindNonMutatingOperations$1.onClick(SolutionStepActivity.kt:55) 
        at android.view.View.performClick(View.java:7870) 
        at android.view.View.performClickInternal(View.java:7839) 
        at android.view.View.access$3600(View.java:886) 
        at android.view.View$PerformClick.run(View.java:29363) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:237) 
        at android.app.ActivityThread.main(ActivityThread.java:7948) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1075) 

I have considered dexing my uberjar to allow it to work with Android's dalvik JVM in case that's the issue but I am unsure of how to proceed after obtaining a jar containing classes.dex of my Clojure program after running:

dx --dex --min-sdk-version="26" --output=".\MMAST.jar" "C:\path\to\foobar-0.1.0-SNAPSHOT-standalone.jar"

Is there a way to fix this or some other way of integrating Clojure into my Android project?

Delarge
  • 21
  • 4
  • 2
    Have you looked at https://stackoverflow.com/questions/4651757/clojure-on-android and https://stackoverflow.com/questions/2181774/calling-clojure-from-java and https://stackoverflow.com/questions/53358433/how-does-one-invoke-clojure-on-android? – Bob Jarvis - Слава Україні Apr 11 '21 at 16:21
  • Yes, I should have mentioned my search attempts but the first post is specifically about Clojure frameworks for android and the second post is not an issue as I am able to run clojure code from kotlin scripts/java programs but not on android as mentioned. The third question is similar to my issue but to my knowledge I doubt its an issue that can be recitfied with lein as I built my jar with just java 16 on my machine and went unresolved. I was hoping by providing more context I may be able to find a solution to this issue which i was unable to do so via search results. – Delarge Apr 12 '21 at 12:27

0 Answers0