Last active
June 10, 2020 20:33
-
-
Save seancorfield/01e42dbf3de68bab6ef3d7d6245af192 to your computer and use it in GitHub Desktop.
Debugging Reflection Warnings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; I use Clojure CLI / deps.edn and I have these JVM options in an alias | |
;; that use when starting my REPL for testing: | |
:jvm-opts ["-Dclojure.core.async.go-checking=true" | |
"-XX:-OmitStackTraceInFastThrow" | |
"--illegal-access=warn"] | |
;; the last one is relevant to this particular piece of debugging so that | |
;; _all_ illegal reflective access warnings are shown, not just the last | |
;; | |
;; the stacktrace option ensures the JVM doesn't optimize away stack traces | |
;; for commonly thrown exceptions (such as NPE) | |
;; | |
;; the core.async option checks that you don't do blocking ops inside go loops |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; here's my REPL session showing how I debugged it (I run OpenJDK 14 locally) | |
;; | |
;; first off, test the original function as-is: | |
user=> (import '(java.text BreakIterator)) | |
java.text.BreakIterator | |
user=> (def grapheme-length | |
#(->> (doto (BreakIterator/getCharacterInstance) | |
(.setText %)) | |
(partial (memfn next)) | |
repeatedly | |
(take-while (partial not= BreakIterator/DONE)) | |
count)) | |
#'user/grapheme-length | |
user=> (grapheme-length "\uD83D\uDE04⌘\uD83D\uDE00") | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.setText(java.text.CharacterIterator) | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
3 | |
;; address .setText -- https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/BreakIterator.html | |
;; overloaded on String and CharacterIterator so tell it we want the String version: | |
user=> (def grapheme-length | |
#(->> (doto (BreakIterator/getCharacterInstance) | |
(.setText ^String %)) | |
(partial (memfn next)) | |
repeatedly | |
(take-while (partial not= BreakIterator/DONE)) | |
count)) | |
#'user/grapheme-length | |
user=> (grapheme-length "\uD83D\uDE04⌘\uD83D\uDE00") | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
WARNING: Illegal reflective access ... method sun.text.RuleBasedBreakIterator.next() | |
3 | |
;; replace memfn with an explicit function so we can type hint the call: | |
user=> (def grapheme-length | |
#(->> (doto (BreakIterator/getCharacterInstance) | |
(.setText ^String %)) | |
(partial (fn [o] (.next o))) | |
repeatedly | |
(take-while (partial not= BreakIterator/DONE)) | |
count)) | |
#'user/grapheme-length | |
;; omitting confirmation that the call still produces the same four warnings | |
;; now add type hint on o: | |
user=> (def grapheme-length | |
#(->> (doto (BreakIterator/getCharacterInstance) | |
(.setText ^String %)) | |
(partial (fn [^BreakIterator o] (.next o))) | |
repeatedly | |
(take-while (partial not= BreakIterator/DONE)) | |
count)) | |
#'user/grapheme-length | |
user=> (grapheme-length "\uD83D\uDE04⌘\uD83D\uDE00") | |
3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment