Inherited public methods from package-private superclass are not callable via Clojure interop.
I hit this with Google’s https://github.com/google/mug library. The https://google.github.io/mug/apidocs/com/google/mu/util/StringFormat.html#format(java.lang.Object,java.lang.Object) is declared as public final on AbstractStringFormat, which is package-private. StringFormat is public and https://github.com/google/mug/blob/master/mug/src/main/java/com/google/mu/util/StringFormat.java#L86 it.
In Java this works fine — javac emits invokevirtual on the public subclass. In Clojure, all three interop paths fail:
1. Type-hinted call (.format ^StringFormat fmt "a" "b") -> No matching method format found taking 2 args
2. Method reference ^[Object Object] StringFormat/.format -> IllegalAccessError: failed to access class AbstractStringFormat
3. No type hint (reflection) (.format fmt "a" "b") -> same as #1
java.lang.reflect.Method works fine — StringFormat.class.getMethod("format", Object, Object) finds and invokes it without issues.
This looks like https://clojure.atlassian.net/browse/CLJ-1243 (open since 2013). Repro script in thread.
#!/bin/sh
#_(
DEPS='{:deps {com.google.mug/mug {:mvn/version "9.9.9"}}}'
exec clojure -Sdeps "$DEPS" -M "$0" "$@"
)
;;
(import '(com.google.mu.util StringFormat))
(def fmt (StringFormat. "{a}/{b}"))
(println "=== 1 ===")
(try
(eval '(.format ^StringFormat fmt "a" "b"))
(catch Throwable e
(println (str " " (.getClass e) ": " (.getMessage e)))))
(println "=== 2 ===")
(try
(eval '(let [f ^[Object Object] StringFormat/.format]
(f fmt "a" "b")))
(catch Throwable e
(println (str " " (.getClass e) ": " (.getMessage (or (.getCause e) e))))))
(println)
(println "=== 3 ===")
(try
(let [result (.format fmt "a" "b")]
(println (str " result: " result)))
(catch Throwable e
(println (str " " (.getClass e) ": " (.getMessage e)))))
(println)
(println "=== 4 ===")
(let [m (-> StringFormat (.getMethod "format" (into-array Class [Object Object])))]
(.setAccessible m true)
(println (str " result: " (.invoke m fmt (object-array ["a" "b"]))))) I suspect that the way to type hint it would actually be to hint it with the AbstractStringFormat package-private class...
But ofc since it's package private that may cause issues.
Somebody asked for DXML-75 to be fixed in babashka's built-in clojure.data.xml but I don't want to lean on other people's forks if the upstream can be fixed. @alexmiller Any chance this will be looked at soon-ish? https://clojure.atlassian.net/browse/DXML-75
ℹ️ New patch file attached, https://clojure.atlassian.net/browse/DXML-75 updated.
https://clojurians.slack.com/archives/C06MAR553/p1775749510702949
thanks!
thanks for making it non-breaking :)
I dropped a comment there, not sure if OP is available to look at it. It seems like the patch could be made non-breaking and that would be better, then I would not have a problem merging
Cc @ramart