Clojure与Java互操作:针对com.google.cloud.storage.StorageImpl的实现

4
尝试使用https://github.com/googleapis/google-cloud-java/blob/master/google-cloud-clients/google-cloud-storage/src/main/java/com/google/cloud/storage/StorageImpl.java#L139进行Java互操作 - 使用字节数组的create方法。
在我的REPL中有以下内容:
user=> (->> s r/reflect :members 
               (filter #(instance? clojure.reflect.Method %)) 
               (filter #(:public (:flags %))) 
               (filter #(= (str (:name %)) "create")) 
               (print-table [:name :flags :parameter-types]))

|  :name |              :flags |                                                                                           :parameter-types |
|--------+---------------------+------------------------------------------------------------------------------------------------------------|
| create | #{:varargs :public} |             [com.google.cloud.storage.BlobInfo byte<> com.google.cloud.storage.Storage$BlobTargetOption<>] |

(还有其他的,但这似乎是最相关的。)
另外:
user=> s
#object[com.google.cloud.storage.StorageImpl 0x57fb59c8 "com.google.cloud.storage.StorageImpl@57fb59c8"]
user=> blob-info
#object[com.google.cloud.storage.BlobInfo$BuilderImpl 0x1e8ce729 "com.google.cloud.storage.BlobInfo$BuilderImpl@1e8ce729"]
user=> b
#whidbey/bin "SEVZIE1ZIEdVWQ==“

但是当我调用.create时,我得到:
user=> (.create s blob-info (bytes b))

java.lang.IllegalArgumentException: No matching method create found taking 2 args for class com.google.cloud.storage.StorageImpl

如果我尝试将nil作为第三个参数添加,我会得到与3 args相同的错误。
我是否漏掉了什么明显的东西?谢谢!
编辑:如何在Clojure中处理Java可变长度参数?非常相似,并且更通用(这很好)。 这个问题最终成为关于一个特定的create函数签名的具体问题。

可能是如何在Clojure中处理Java可变长度参数?的重复问题。 - cfrick
你喜欢的那个函数不是使用两个参数,而是三个。在Java中,你可以只用两个参数调用它,因为编译器会处理。JVM始终会采用第三个参数;即使为空,也是该类型的数组。 - cfrick
2个回答

4
答案是(来自clojurians slack上的seancorfield)blob-info实际上是一个BuilderImpl内部类,并且需要成为一个真正的BlobInfo。能够工作的代码如下:
(defn get-storage []
  (-> (StorageOptions/getDefaultInstance)
      (.getService)))

(defn get-blob-info [bucket storage-key]
  (let [content-type "text/plain"
        blob-id (BlobId/of bucket storage-key)
        builder (doto
                  (BlobInfo/newBuilder blob-id)
                  (.setContentType content-type))]

    (.build builder)))

(defn upload-str [bucket storage-key str-to-store]
  (let [storage (get-storage)
        blob-info (get-blob-info bucket storage-key)
        byte-arr (.getBytes str-to-store)]
    (.create storage
             blob-info
             byte-arr
             (into-array Storage$BlobTargetOption []))))

没有必要使用类型提示 - 只需要让类型正确对应即可。

啊,太高兴发现这个了!谢谢。 - Stepan Parunashvili

1

我不确定(bytes b)是否是正确的语法(#whidbey/bin是什么?)。

也许可以尝试

(byte-array [1 2 3]) 

或类似的。您还可以尝试对参数进行类型提示:

(.create s 
    blob-info
    ^"[B" (byte-array [1 2 3])    ; type-hinted param
)

更新

这里是我认为你需要的类型提示的示例:

(let [byte-array-obj  (byte-array [1 2 3])
      sss             (java.util.Arrays/toString  ^"[B"  byte-array-obj) ]
    (spyxx byte-array-obj)
    (spyx (type byte-array-obj))
    (spyx (aget byte-array-obj 2))
    (spyx sss))

带有结果的:


byte-array-obj => <#[B #object["[B" 0x26071f95 "[B@26071f95"]>
(type byte-array-obj) => [B
(aget byte-array-obj 2) => 3
sss => "[1, 2, 3]"

请注意,Clojure有一种简单的方法来进行类型提示,而不需要采用java-native的"[B"字符串语法。
(java.util.Arrays/toString ^"[B"  byte-array-obj)  ; type hint using a string
(java.util.Arrays/toString ^bytes byte-array-obj)  ; Clojure "build-in" type hint 

两者都是相等的。


https://github.com/greglook/whidbey - 这是我从 Docker 容器中使用的 REPL 中获取的。将其转换为字节数组并没有起作用。这似乎与 Clojure 能够通过其签名在类上找到函数有关,而我在正确的咒语方面遇到了麻烦。 - Hoopes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接