{"id":15673176,"url":"https://github.com/borkdude/clj-reflector-graal-java11-fix","last_synced_at":"2025-05-06T21:49:27.222Z","repository":{"id":54765705,"uuid":"246121188","full_name":"borkdude/clj-reflector-graal-java11-fix","owner":"borkdude","description":"A fix for an issue with clojure.lang.Reflector in GraalVM native-image JDK11.","archived":false,"fork":false,"pushed_at":"2021-02-04T19:30:58.000Z","size":32,"stargazers_count":15,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-19T15:33:47.659Z","etag":null,"topics":["clojure","graalvm","native-image"],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/borkdude.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-03-09T19:13:56.000Z","updated_at":"2022-05-31T04:00:44.000Z","dependencies_parsed_at":"2022-08-14T02:10:33.806Z","dependency_job_id":null,"html_url":"https://github.com/borkdude/clj-reflector-graal-java11-fix","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fclj-reflector-graal-java11-fix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fclj-reflector-graal-java11-fix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fclj-reflector-graal-java11-fix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borkdude%2Fclj-reflector-graal-java11-fix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/borkdude","download_url":"https://codeload.github.com/borkdude/clj-reflector-graal-java11-fix/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252776506,"owners_count":21802463,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","graalvm","native-image"],"created_at":"2024-10-03T15:38:08.258Z","updated_at":"2025-05-06T21:49:27.189Z","avatar_url":"https://github.com/borkdude.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# clj-reflector-graal-java11-fix\n\n***\n:tada: **Great news!** Starting with GraalVM v21, this fix should no longer be needed.\n***\n\nInstead, you will probably need to add this to your [reflection](https://github.com/oracle/graal/blob/master/substratevm/Reflection.md) config:\n\n``` json\n[{\"name\": \"java.lang.reflect.AccessibleObject\",\n  \"methods\" : [{\"name\":\"canAccess\"}]},\n  ...\n]\n```\n\n[![Clojars Project](https://img.shields.io/clojars/v/borkdude/clj-reflector-graal-java11-fix.svg)](https://clojars.org/borkdude/clj-reflector-graal-java11-fix)\n\nThis library offers a fix for an issue with `clojure.lang.Reflector` when used\ntogether with GraalVM `native-image` on java11.\n\n## Usage\n\nInclude this library in your leiningen profile or deps.edn alias so it's\navailable on the classpath for GraalVM `native-image`. \n\nImportant:\n\n- Use the right GraalVM version modifier: e.g. `graalvm-20.3.0`. The modifier must exactly match the version of GraalVM\n`native-image` you are using.\n- Do NOT distribute this library as part of libraries or applications that are run\nwith a JVM. Use it for compiling to native binaries only.\n\n### Leiningen\n\nRelevant config for `project.cljc`:\n``` clojure\n(defproject foo \"0.0.1-SNAPSHOT\"\n  :profiles {:native-image {:dependencies [[borkdude/clj-reflector-graal-java11-fix \"0.0.1-graalvm-20.3.0\"]]}})\n```\n\nTo produce an uberjar that is fed to `native-image` you can:\n\n``` shell\n$ lein with-profiles +native-image do clean, uberjar\n```\n\nand then:\n\n``` shell\n$ native-image -jar target/foo-0.0.1-SNAPSHOT-standalone.jar\n```\n\n### Tools Deps\n\nRelevant config for `deps.edn`:\n``` clojure\n{:aliases\n {:native-image {:extra-deps {borkdude/clj-reflector-graal-java11-fix\n                              {:mvn/version \"0.0.1-graalvm-20.3.0\"\n                               :exclusions [org.graalvm.nativeimage/svm]}}}}}\n```\n\nNotice the exclusion? This project depends on native dep `org.graalvm.nativeimage/svm`.\nWhile technically correct, tools deps does not support native deps and fails for this native dep.\nSince the native dep is provided by the Graal installation anyway, it can be safely excluded for tools deps.\n\nYour compile script would get the classspath for `native-image` via:\n\n```shell\nclojure -A:native-image -Spath\n```\n\n## The problem\n\nJDK11 is supported since GraalVM 19.3.0. The class `clojure.lang.Reflector` uses\na `MethodHandle` to maintain compatibility with java8 and java11 at the same\ntime:\n\n``` java\nstatic {\n\tMethodHandle pred = null;\n\ttry {\n\t\tif (! isJava8())\n\t\t\tpred = MethodHandles.lookup().findVirtual(Method.class, \"canAccess\", MethodType.methodType(boolean.class, Object.class));\n\t} catch (Throwable t) {\n\t\tUtil.sneakyThrow(t);\n\t}\n\tCAN_ACCESS_PRED = pred;\n}\n```\n\nGraalVM does not support `MethodHandle`s that cannot be analyzed as a compile\ntime constant. It will complain when it analyzes `clojure.lang.Reflector` on\nJDK11:\n\n``` java\nException in thread \"main\" com.oracle.svm.core.jdk.UnsupportedFeatureError: Invoke with MethodHandle argument could not be reduced to at most a single call or single field access. The method handle must be a compile time constant, e.g., be loaded from a `static final` field. Method that contains the method handle invocation: java.lang.invoke.Invokers$Holder.invoke_MT(Object, Object, Object, Object)\n    at com.oracle.svm.core.util.VMError.unsupportedFeature(VMError.java:101)\n    at clojure.lang.Reflector.canAccess(Reflector.java:49)\n    ...\n```\n\nSee the [issue](https://github.com/oracle/graal/issues/2214) on the GraalVM\nrepo.\n\n## The solution\n\nGraalVM supports substitutions. For JDK11 or later the method `canAccess` is replaced as follows:\n\n``` java\n@TargetClass(className = \"clojure.lang.Reflector\")\nfinal class Target_clojure_lang_Reflector {\n\n    @Substitute\n    @TargetElement(onlyWith = JDK11OrLater.class)\n    private static boolean canAccess(Method m, Object target) {\n        // JDK9+ use j.l.r.AccessibleObject::canAccess, which respects module rules\n        try {\n            return (boolean) m.canAccess(target);\n        } catch (Throwable t) {\n            throw Util.sneakyThrow(t);\n        }\n    }\n}\n```\n\n## License\n\nCopyright © 2020 Michiel Borkent\n\nDistributed under the EPL License. See LICENSE.\n\nThis project contains code from:\n- Clojure, which is licensed under the same EPL License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborkdude%2Fclj-reflector-graal-java11-fix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fborkdude%2Fclj-reflector-graal-java11-fix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborkdude%2Fclj-reflector-graal-java11-fix/lists"}