Fork me on GitHub
#java
<
2021-12-04
>
jjttjj20:12:20

I'm trying to call a method on a static inner class. I have imported the inner class and its parent class (not sure of the terminology here) . I get an instance of the inner class, and reflection shows that it has the methods I want to invoke, yet I keep getting "No matching method" errors when trying to invoke them. Any tips?

;;; 
;;; 
(import '(org.web3j.crypto
           StructuredDataEncoder
           StructuredData
           StructuredData$EIP712Message))
(let [sde (StructuredDataEncoder. valid-json-str)
      ^StructuredData$EIP712Message msg 
      ;;returns a StructuredData$EIP712Message
      (.jsonMessageObject sde)]
  ;; the msg has getMessage and getPrimaryType methods with zero arguments:
  (run! println
    (-> msg class .getMethods (->> (map str) (filter #(re-find #"\.get.+" %)))))
  ;; prints:
  ;; public java.lang.Object org.web3j.crypto.StructuredData$EIP712Message.getMessage()
  ;; public java.lang.String org.web3j.crypto.StructuredData$EIP712Message.getPrimaryType()
  ;; ...

  ;; however, both of these fail
  (.getPrimaryType msg) ;; (.getMessage msg)  also fails
  ;; IllegalArgumentException No matching method getPrimaryType found taking 0 args for class org.web3j.crypto.StructuredData$EIP712Message

  )
Edit: maven dep is
org.web3j/core {:mvn/version "4.8.9"}

seancorfield20:12:31

@jjttjj I don't see anything obvious wrong with it. I can't test it in a REPL without knowing what valid-json-str is tho'... I tried but clearly that's a very specific structure?

jjttjj20:12:24

@seancorfield Yes, sorry this is the valid-json-str

(def valid-json-str
  "{
   \"types\"       : {
                    \"EIP712Domain\" : [
                                      {\"name\" : \"name\", \"type\" : \"string\"},
                                      {\"name\" : \"version\", \"type\" : \"string\"},
                                      {\"name\" : \"chainId\", \"type\" : \"uint256\"},
                                      {\"name\" : \"verifyingContract\", \"type\" : \"address\"}
                                     ],
                    \"Person\"       : [
                                      {\"name\" : \"name\", \"type\" : \"string\"},
                                      {\"name\" : \"wallet\", \"type\" : \"address\"}
                               ],
                    \"Mail\"         : [
                                      {\"name\" : \"from\", \"type\" : \"Person\"},
                                      {\"name\" : \"to\", \"type\" : \"Person\"},
                                      {\"name\" : \"contents\", \"type\" : \"string\"}
                             ]
                    },
   \"primaryType\" : \"Mail\",
   \"domain\"      : {
                    \"name\"              : \"Ether Mail\",
                    \"version\"           : \"1\",
                    \"chainId\"           : 1,
                    \"verifyingContract\" : \"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"
                    },
   \"message\"     : {
               \"from\": {
                        \"name\": \"Cow\",
                        \"wallet\": \"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"
                        },
               \"to\": {
                      \"name\": \"Bob\",
                      \"wallet\": \"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"
                      },
               \"contents\": \"Hello, Bob!\"
               }
   }")

seancorfield21:12:07

I wonder if this is because that inner class is static?

seancorfield21:12:10

You can call .toString() which is an override from Object I guess.

seancorfield21:12:35

I wonder if this might be a limitation of Clojure's interop?

jjttjj22:12:05

Could be. I might try to dig deeper at some point and possibly post an ask.clojure question. Thanks for verify my sanity for now though!

Alex Miller (Clojure team)22:12:51

The static inner class isn't public

seancorfield22:12:03

Dang! Totally missed that. Thanks @alexmiller

jjttjj22:12:28

That's it! Thanks.

(let [m (->>
          StructuredData$EIP712Message
          .getMethods
          vec
          (some (fn [x]
                  (when (= (.getName x) "getMessage") x)))
          )]
  (.setAccessible m true)
  (.invoke m
    (.jsonMessageObject (StructuredDataEncoder. valid-json-str))
    (into-array [])))

;; =>
#object[java.util.LinkedHashMap
        "0x36ee2fe"
        "{from={name=Cow, wallet=0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826}, to={name=Bob, wallet=0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB}, contents=Hello, Bob!}"]

Alex Miller (Clojure team)22:12:21

Note that setAccesible will not work on all jdk versions or all permission sets, so generally better to find out how the author wants you to use the api if possible

emccue22:12:43

the “proper” way to do something like this is for the library to give you a object

emccue22:12:44

but it really doesn’t seem like from your example you are getting any value out of those classes