How to implement a multimethod for a collection of type like Map<javaType, javaType>
? Something like this:
(defmethod multimethod Map<javaType,javaType> [map]
{(.key (first map)) (.value (first map))})
Maybe the question above is not the solution I need to solve my problem (it's just I think that the implementation with generics can solve my problem), so I think I need to provide the whole explanation of what is my problem and ask community what I need to do.
I work with a java library in Clojure. Some functions return me java classes that I want to convert to clojure maps. I'm doing this with java.data library.
In most of cases this works fine. For some reason I need to implement java.data multimethod for several classes:
;; From java.data readme
(defmethod from-java YourJavaClass [instance]
; your custom logic for turing this instance into a clojure data structure)
But it's okay and this works fine:
(defmethod jd/from-java CurrencyPair [instance]
(help/convert-market-keyword (.toString instance)))
But I encountered some class that can't be "mapped" for some reason.
(defmethod jd/from-java AccountInfo [instance]
{:myWallet (jd/from-java (.getWallet instance))})
(defmethod jd/from-java Wallet [instance]
{:myBalances (jd/from-java (.getBalances instance))})
(defmethod jd/from-java Balance [instance]
"BALANCE!!!!")
(defmethod jd/from-java Currency [instance]
;; e.g. converts Currency instance with field "BTC" to keyword :btc
(help/convert-currency-keyword (.toString instance)))
After mapping an AccountInfo
instance I expect to see this:
{:myWallet
{:myBalances
{:btc "BALANCE!!!!"
:eth "BALANCE!!!!"
:usdt "BALANCE!!!!"
...}
But see this:
{:myWallet
{:myBalances
{#object[org.knowm.xchange.currency.Currency 0x4faae851 "BTC"]
#object[org.knowm.xchange.dto.account.Balance 0x42942aa9 "Balance [currency=GNT, total=null, available=0E-8, frozen=0E-8, borrowed=0, loaned=0, withdrawing=0, depositing=0]"],
#object[org.knowm.xchange.currency.Currency 0x299d00e0 "ETH"]
#object[org.knowm.xchange.dto.account.Balance 0x23f7cb1d "Balance [currency=LSK, total=null, available=0E-8, frozen=0E-8, borrowed=0, loaned=0, withdrawing=0, depositing=0]"],
...}
The returning value type of .getBalances()
is Map<Currency,Balance>
and it seems java.data don't know how to work with maps.
So, my question (at the moment) is how to implement the java.data multimethod for this kind of collection. Something like this:
(defmethod jd/from-java Map<Currency,Balance> [instance]
{:cur "BALANCE!!!!"})
Just in case, the java library is XChange. The problem with Wallet class. Method getBalances().
As noted in the comments, using "generic types" at runtime is probably a non-starter. However, it appears that the java.data library does not call from-java
recursively on keys and values in Map
instances. The default implementation of from-java
for Map
is just (into {} instance)
. Perhaps the specific problem the OP is facing can be solved by redefining from-java
method for java.util.Map
. The new implementation would apply from-java
to all keys and values. For example:
(defmethod jd/from-java java.util.Map
[m]
(zipmap (map jd/from-java (keys m)) (map jd/from-java (vals m))))