Hi,
I'm porting some JDK 8 code to JDK 9 and hit a snag that boils down to "an interface, of which I tried to implement all the methods, suddenly grew a few static methods and deftype doesn't know how to do that". I tried ^:static and ^{:static true}.
You can try this as follows: java.util.Map grew a handful of static methods in JDK9 where previously it had none. Try:
(deftype MyMap [obj]
java.util.Map
^{:static true} (entry [k v] nil))
This fails, saying there's no `entry` method in java.util.Map. (There is, at least on JDK9! But it's static.) I have also tried putting the metadata on the method name symbol and the params, but no dice.
Underlying context need: Clojure's maps are both iterable and associative, implementing both Java interfaces. The GCP StackDriver code that tries to serialize values typechecks to figure out what to do with a type, but it typechecks in the wrong order: it checks for iterability before associativity. So it treats {} as a seq and that works but it looks terrible in the logs. Hence, I have a silly macro that generates a silly stub class that only implements the 1 right interface and proxies all method calls to the Clojure datatype. Here's the implementation of that macro and a sample use case:
(defmacro defproxytype
[type-name iface-sym]
(let [iface (Class/forName (str iface-sym))
{:keys [members]} (refl/reflect iface)
wrapped-obj '(.-obj this)]
`(deftype ~type-name [~(with-meta 'obj {:tag iface})]
~iface-sym
~@(for [{:keys [name parameter-types return-type]} members
:let [m (with-meta (symbol name) {:tag return-type})
args (map (fn [arg-idx arg-type]
(with-meta
(symbol (str "arg" arg-idx))
{:tag arg-type}))
(range) parameter-types)]]
`(~m [~'this ~@args] (. ~wrapped-obj ~m ~@args))))))
(defproxytype JustAMap java.util.Map)
Then, I walk the tree and wrap all maps with ->JustAMap. As you can see, while technically I might be able to use gen-class somehow, this is something where deftype shines :-) Fortunately right now the caller doesn't use any of the static methods and generally speaking I'd expect them not to (kind of by definition) -- so my workaround is just to not implement any of the static methods and hope for the best. Still, if there's a way, I'd love to know :)
lvh