diff --git a/README.md b/README.md index 65771518..41656763 100644 --- a/README.md +++ b/README.md @@ -520,6 +520,10 @@ You need [Leiningen](https://leiningen.org/), and for building binaries you need `lein repl` will get you a standard REPL/nREPL connection. To work on tests use `lein with-profiles +test repl`. +### Generate reflection.json file + + lein with-profiles +reflection run + ### Test Test on the JVM (for development): diff --git a/project.clj b/project.clj index 4703e378..07cdfa04 100644 --- a/project.clj +++ b/project.clj @@ -21,7 +21,8 @@ :jvm-opts ["-Dclojure.compiler.direct-linking=true" "-Dclojure.spec.skip-macros=true"] :main babashka.main - :aot :all}} + :aot :all} + :reflection {:main babashka.impl.classes/generate-reflection-file}} :aliases {"bb" ["run" "-m" "babashka.main"]} :deploy-repositories [["clojars" {:url "https://clojars.org/repo" :username :env/clojars_user diff --git a/reflection.json b/reflection.json index a41c3fcd..63f3b320 100644 --- a/reflection.json +++ b/reflection.json @@ -1,185 +1,214 @@ -[ - { - "name":"java.lang.ArithmeticException", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.AssertionError", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.Boolean", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.io.BufferedWriter", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.io.BufferedReader", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name": "java.lang.Class", - "allDeclaredConstructors": true, - "allPublicConstructors": true, - "allDeclaredMethods": true, - "allPublicMethods": true - }, - { - "name":"java.lang.Double", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.Exception", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name": "clojure.lang.ExceptionInfo", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.Integer", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.io.File", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"clojure.lang.LineNumberingPushbackReader", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.util.concurrent.LinkedBlockingQueue", - "allPublicMethods":true - }, - { - "name":"java.util.regex.Pattern", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.Process", - "allPublicMethods":true - }, - { - "name":"java.lang.ProcessBuilder", - "allPublicConstructors":true - }, - { - "name":"java.lang.String", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.io.StringReader", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.io.StringWriter", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.System", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.Thread", - "methods": [{"name":"run"},{"name":"toString"},{"name":"isInterrupted"},{"name":"currentThread"},{"name":"getName"},{"name":"join"},{"name":"getThreadGroup"},{"name":"getStackTrace"},{"name":"holdsLock"},{"name":"checkAccess"},{"name":"dumpStack"},{"name":"yield"},{"name":"setPriority"},{"name":"setDaemon"},{"name":"start"},{"name":"sleep"},{"name":"interrupt"},{"name":"interrupted"},{"name":"isAlive"},{"name":"getPriority"},{"name":"setName"},{"name":"activeCount"},{"name":"enumerate"},{"name":"isDaemon"},{"name":"getContextClassLoader"},{"name":"setContextClassLoader"},{"name":"getAllStackTraces"},{"name":"getId"},{"name":"getState"},{"name":"setDefaultUncaughtExceptionHandler"},{"name":"getDefaultUncaughtExceptionHandler"},{"name":"getUncaughtExceptionHandler"},{"name":"setUncaughtExceptionHandler"}], - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.lang.UNIXProcess", - "allPublicMethods":true - }, - { - "name":"java.nio.file.attribute.FileAttribute", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.attribute.PosixFilePermission", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.attribute.PosixFilePermissions", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.Path", - "allPublicMethods":true - }, - { - "name":"java.nio.file.CopyOption", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.FileAlreadyExistsException", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.Files", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.NoSuchFileException", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"java.nio.file.StandardCopyOption", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - }, - { - "name":"sun.nio.fs.UnixPath", - "allPublicMethods":true, - "allPublicFields": true, - "allPublicConstructors": true - } -] +[ { + "name" : "clojure.lang.ExceptionInfo", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "clojure.lang.LineNumberingPushbackReader", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.BufferedReader", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.BufferedWriter", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.File", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.StringReader", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.io.StringWriter", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.ArithmeticException", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.AssertionError", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Boolean", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Class", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Double", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Exception", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.Integer", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.String", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.lang.System", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.CopyOption", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.FileAlreadyExistsException", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.Files", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.NoSuchFileException", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.Path", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.StandardCopyOption", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.attribute.FileAttribute", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.attribute.PosixFilePermission", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.nio.file.attribute.PosixFilePermissions", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "java.util.regex.Pattern", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "name" : "sun.nio.fs.UnixPath", + "allPublicMethods" : true, + "allPublicFields" : true, + "allPublicConstructors" : true +}, { + "allPublicMethods" : true, + "name" : "java.util.concurrent.LinkedBlockingQueue" +}, { + "allPublicConstructors" : true, + "name" : "java.lang.Process" +}, { + "allPublicMethods" : true, + "name" : "java.lang.UNIXProcess" +}, { + "methods" : [ { + "name" : "activeCount" + }, { + "name" : "checkAccess" + }, { + "name" : "currentThread" + }, { + "name" : "dumpStack" + }, { + "name" : "enumerate" + }, { + "name" : "getAllStackTraces" + }, { + "name" : "getContextClassLoader" + }, { + "name" : "getDefaultUncaughtExceptionHandler" + }, { + "name" : "getId" + }, { + "name" : "getName" + }, { + "name" : "getPriority" + }, { + "name" : "getStackTrace" + }, { + "name" : "getState" + }, { + "name" : "getThreadGroup" + }, { + "name" : "getUncaughtExceptionHandler" + }, { + "name" : "holdsLock" + }, { + "name" : "interrupt" + }, { + "name" : "interrupted" + }, { + "name" : "isAlive" + }, { + "name" : "isDaemon" + }, { + "name" : "isInterrupted" + }, { + "name" : "join" + }, { + "name" : "run" + }, { + "name" : "setContextClassLoader" + }, { + "name" : "setDaemon" + }, { + "name" : "setDefaultUncaughtExceptionHandler" + }, { + "name" : "setName" + }, { + "name" : "setPriority" + }, { + "name" : "setUncaughtExceptionHandler" + }, { + "name" : "sleep" + }, { + "name" : "start" + }, { + "name" : "toString" + }, { + "name" : "yield" + } ], + "name" : "java.lang.Thread" +} ] \ No newline at end of file diff --git a/reflection.json.bak b/reflection.json.bak new file mode 100644 index 00000000..a41c3fcd --- /dev/null +++ b/reflection.json.bak @@ -0,0 +1,185 @@ +[ + { + "name":"java.lang.ArithmeticException", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.AssertionError", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.Boolean", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.io.BufferedWriter", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.io.BufferedReader", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name": "java.lang.Class", + "allDeclaredConstructors": true, + "allPublicConstructors": true, + "allDeclaredMethods": true, + "allPublicMethods": true + }, + { + "name":"java.lang.Double", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.Exception", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name": "clojure.lang.ExceptionInfo", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.Integer", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.io.File", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"clojure.lang.LineNumberingPushbackReader", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.util.concurrent.LinkedBlockingQueue", + "allPublicMethods":true + }, + { + "name":"java.util.regex.Pattern", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.Process", + "allPublicMethods":true + }, + { + "name":"java.lang.ProcessBuilder", + "allPublicConstructors":true + }, + { + "name":"java.lang.String", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.io.StringReader", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.io.StringWriter", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.System", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.Thread", + "methods": [{"name":"run"},{"name":"toString"},{"name":"isInterrupted"},{"name":"currentThread"},{"name":"getName"},{"name":"join"},{"name":"getThreadGroup"},{"name":"getStackTrace"},{"name":"holdsLock"},{"name":"checkAccess"},{"name":"dumpStack"},{"name":"yield"},{"name":"setPriority"},{"name":"setDaemon"},{"name":"start"},{"name":"sleep"},{"name":"interrupt"},{"name":"interrupted"},{"name":"isAlive"},{"name":"getPriority"},{"name":"setName"},{"name":"activeCount"},{"name":"enumerate"},{"name":"isDaemon"},{"name":"getContextClassLoader"},{"name":"setContextClassLoader"},{"name":"getAllStackTraces"},{"name":"getId"},{"name":"getState"},{"name":"setDefaultUncaughtExceptionHandler"},{"name":"getDefaultUncaughtExceptionHandler"},{"name":"getUncaughtExceptionHandler"},{"name":"setUncaughtExceptionHandler"}], + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.lang.UNIXProcess", + "allPublicMethods":true + }, + { + "name":"java.nio.file.attribute.FileAttribute", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.attribute.PosixFilePermission", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.attribute.PosixFilePermissions", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.Path", + "allPublicMethods":true + }, + { + "name":"java.nio.file.CopyOption", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.FileAlreadyExistsException", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.Files", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.NoSuchFileException", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"java.nio.file.StandardCopyOption", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + }, + { + "name":"sun.nio.fs.UnixPath", + "allPublicMethods":true, + "allPublicFields": true, + "allPublicConstructors": true + } +] diff --git a/src/babashka/impl/classes.clj b/src/babashka/impl/classes.clj new file mode 100644 index 00000000..16736baf --- /dev/null +++ b/src/babashka/impl/classes.clj @@ -0,0 +1,118 @@ +(ns babashka.impl.classes + {:no-doc true} + (:require + [cheshire.core :as json])) + +(def classes + {:default-classes '[java.lang.ArithmeticException + java.lang.AssertionError + java.lang.Boolean + java.io.BufferedWriter + java.io.BufferedReader + java.lang.Class + java.lang.Double + java.lang.Exception + clojure.lang.ExceptionInfo + java.lang.Integer + java.io.File + clojure.lang.LineNumberingPushbackReader + java.util.regex.Pattern + java.lang.String + java.io.StringReader + java.io.StringWriter + java.lang.System + sun.nio.fs.UnixPath + java.nio.file.attribute.FileAttribute + java.nio.file.attribute.PosixFilePermission + java.nio.file.attribute.PosixFilePermissions + java.nio.file.CopyOption + java.nio.file.FileAlreadyExistsException + java.nio.file.Files + java.nio.file.NoSuchFileException + java.nio.file.Path + java.nio.file.StandardCopyOption] + :custom-classes {'java.util.concurrent.LinkedBlockingQueue ;; why? + {:allPublicMethods true} + 'java.lang.Process ;; for conch? + {:allPublicConstructors true} + 'java.lang.UNIXProcess ;; for conch? + {:allPublicMethods true} + 'java.lang.Thread + ;; generated with `public-declared-method-names`, see in + ;; `comment` below + {:methods [{:name "activeCount"} + {:name "checkAccess"} + {:name "currentThread"} + {:name "dumpStack"} + {:name "enumerate"} + {:name "getAllStackTraces"} + {:name "getContextClassLoader"} + {:name "getDefaultUncaughtExceptionHandler"} + {:name "getId"} + {:name "getName"} + {:name "getPriority"} + {:name "getStackTrace"} + {:name "getState"} + {:name "getThreadGroup"} + {:name "getUncaughtExceptionHandler"} + {:name "holdsLock"} + {:name "interrupt"} + {:name "interrupted"} + {:name "isAlive"} + {:name "isDaemon"} + {:name "isInterrupted"} + {:name "join"} + {:name "run"} + {:name "setContextClassLoader"} + {:name "setDaemon"} + {:name "setDefaultUncaughtExceptionHandler"} + {:name "setName"} + {:name "setPriority"} + {:name "setUncaughtExceptionHandler"} + {:name "sleep"} + {:name "start"} + {:name "toString"} + {:name "yield"}]}}}) + +(defmacro gen-class-map [] + (let [classes (concat (:default-classes classes) + (keys (:custom-classes classes)))] + (apply hash-map + (for [c classes + c [(list 'quote c) c]] + c)))) + +(def class-map (gen-class-map)) + +(defn generate-reflection-file + "Generate reflection.json file" + [& args] + (let [entries (vec (for [c (sort (:default-classes classes))] + {:name (str c) + :allPublicMethods true + :allPublicFields true + :allPublicConstructors true})) + custom-entries (for [[k v] (:custom-classes classes)] + (assoc v :name (str k))) + all-entries (concat entries custom-entries)] + (spit (or + (first args) + "reflection.json") (json/generate-string all-entries {:pretty true})))) + +(comment + + (defn public-declared-method? [c m] + (and (= c (.getDeclaringClass m)) + (not (.getAnnotation m Deprecated)))) + + (defn public-declared-method-names [c] + (->> (.getMethods c) + (keep (fn [m] + (when (public-declared-method? c m) + {:name (.getName m)})) ) + (distinct) + (sort-by :name) + (vec))) + + (public-declared-method-names java.lang.Thread) + ) diff --git a/src/babashka/main.clj b/src/babashka/main.clj index 392436b4..9e4f36c4 100644 --- a/src/babashka/main.clj +++ b/src/babashka/main.clj @@ -14,6 +14,7 @@ [babashka.impl.tools.cli :refer [tools-cli-namespace]] [babashka.impl.utils :refer [eval-string]] [babashka.impl.classpath :as cp] + [babashka.impl.classes :as classes] [babashka.wait :as wait] [clojure.edn :as edn] [clojure.java.io :as io] @@ -256,34 +257,7 @@ Everything after that is bound to *command-line-args*.")) 'System/exit exit} :env env :features #{:bb} - :classes {'java.lang.ArithmeticException ArithmeticException - 'java.lang.AssertionError AssertionError - 'java.lang.Boolean Boolean - 'java.io.BufferedWriter java.io.BufferedWriter - 'java.io.BufferedReader java.io.BufferedReader - 'java.lang.Class Class - 'java.lang.Double Double - 'java.lang.Exception Exception - 'clojure.lang.ExceptionInfo clojure.lang.ExceptionInfo - 'java.lang.Integer Integer - 'java.io.File java.io.File - 'clojure.lang.LineNumberingPushbackReader clojure.lang.LineNumberingPushbackReader - 'java.util.regex.Pattern java.util.regex.Pattern - 'java.lang.String String - 'java.io.StringReader java.io.StringReader - 'java.io.StringWriter java.io.StringWriter - 'java.lang.System System - 'java.lang.Thread Thread - 'sun.nio.fs.UnixPath sun.nio.fs.UnixPath - 'java.nio.file.attribute.FileAttribute java.nio.file.attribute.FileAttribute - 'java.nio.file.attribute.PosixFilePermission java.nio.file.attribute.PosixFilePermission - 'java.nio.file.attribute.PosixFilePermissions java.nio.file.attribute.PosixFilePermissions - 'java.nio.file.CopyOption java.nio.file.CopyOption - 'java.nio.file.FileAlreadyExistsException java.nio.file.FileAlreadyExistsException - 'java.nio.file.Files java.nio.file.Files - 'java.nio.file.NoSuchFileException java.nio.file.NoSuchFileException - 'java.nio.file.StandardCopyOption java.nio.file.StandardCopyOption - } + :classes classes/class-map :imports '{ArithmeticException java.lang.ArithmeticException AssertionError java.lang.AssertionError Boolean java.lang.Boolean