java

2021-12-04T20:03:20.010300Z

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"}

seancorfield 2021-12-04T20:42:31.011600Z

@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?

2021-12-04T20:44:24.012100Z

@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!\"
               }
   }")

seancorfield 2021-12-04T21:32:07.012600Z

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

seancorfield 2021-12-04T21:33:10.013100Z

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

seancorfield 2021-12-04T21:33:35.013500Z

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

2021-12-04T22:04:05.014Z

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) 2021-12-04T22:04:51.014400Z

The static inner class isn't public

seancorfield 2021-12-04T22:17:03.014900Z

Dang! Totally missed that. Thanks @alexmiller

2021-12-04T22:17:28.015300Z

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) 2021-12-04T22:34:21.017Z

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

emccue 2021-12-04T22:46:43.017500Z

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

emccue 2021-12-04T22:47:44.018100Z

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