Fork me on GitHub
#java
<
2019-02-25
>
seancorfield00:02:16

So it's (.create s blob-info (bytes b) (into-array BlogTargetOption []))

hoopes02:02:23

user=> (.create s blob-info (bytes b) (into-array Storage$BlobTargetOption []))

java.lang.IllegalArgumentException: No matching method create found taking 3 args for class com.google.cloud.storage.StorageImpl
user=> 

hoopes02:02:00

variadic is the ellipsis after the BlobTargetOption, ya?

hoopes02:02:51

got the same exception when using just b instead of (bytes b) as well

hoopes02:02:41

i got access to BlobStorageOption from user=> (import [com.google.cloud.storage Storage$BlobTargetOption])

seancorfield03:02:17

@hoopes You may need to type hint blob-info as well... It depends how many overloads create has...

hoopes03:02:58

user=> (.create s [^BlobInfo blob-info] b (into-array Storage$BlobTargetOption []))

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

seancorfield03:02:00

Hmm, it has half a dozen overloads... no wonder it's tough to call 😞

hoopes03:02:08

is that right? just pulled from the java interop page

hoopes03:02:24

this function call is looking funnier and funnier 🙂

seancorfield03:02:28

(.create ^BlobInfo blob-info ...) -- you passed a vector there

hoopes03:02:01

user=> (.create s ^BlobInfo blob-info b (into-array Storage$BlobTargetOption []))

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

hoopes03:02:24

also tried with (bytes b)

hoopes03:02:26

same result

seancorfield03:02:55

I've seen people struggle with Google libraries because of this sort of stuff... ¯\(ツ)/¯

hoopes03:02:14

haha, so obviously i don't want or expect you to sit here and fiddle with this with me, but it IS possible, right?

seancorfield03:02:25

Sure. Definitely possible 🙂

seancorfield03:02:04

I'm happy to try it locally if I know what library you're pulling in (lein/deps coords) and what the code around this looks like

hoopes03:02:07

user=> (set! *warn-on-reflection* true)
true
user=> (.create s ^BlobInfo blob-info (bytes b) ^Storage$BlobTargetOption (into-array Storage$BlobTargetOption []))
Reflection warning, /tmp/form-init4534991595574875173.clj:1:1 - call to method create can't be resolved (target class is unknown).

hoopes03:02:12

does that make any sense?

hoopes03:02:29

[com.google.cloud/google-cloud-storage "1.63.0"]

seancorfield03:02:32

What are s and b?

hoopes03:02:15

(import [com.google.cloud.storage
            StorageOptions
            BlobId
            BlobInfo])

hoopes03:02:54

(def s (-> (StorageOptions/getDefaultInstance) (.getService)))

hoopes03:02:24

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

hoopes03:02:59

(def b (.getBytes "whoa baby"))

seancorfield03:02:37

Dinner time here. Will try the code in 10-15 mins

hoopes03:02:56

would greatly appreciate - i have a new baby, and must go attend, but i will check back

hoopes03:02:01

thanks so very much!

hoopes03:02:10

a hopefully more usable version:

hoopes03:02:12

(ns my-lib.utils.gcp.storage
  (:require [ :as io])
  (:import [com.google.cloud.storage
            StorageOptions
            BlobId
            BlobInfo
            Storage$BlobTargetOption ]))

(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)]
    (doto
      (BlobInfo/newBuilder blob-id)
      (.setContentType content-type)
      (.build))))

(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 []))))

hoopes03:02:39

user=> (require '[my-lib.utils.gcp.storage :as storage])
user=> (storage/upload-str "my-bucket" "some-new-file.txt" "whoa buddy")

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

seancorfield03:02:12

Based on that, you almost certainly need to type hint the get-storage and get-blob-info functions (add a type hint before the arglist).

hoopes03:02:43

(ns my-lib.utils.gcp.storage
  (:require [ :as io])
  (:import [com.google.cloud.storage
            Storage
            StorageOptions
            BlobId
            BlobInfo
            Storage$BlobTargetOption ])) 

(defn get-storage ^Storage []
  (-> (StorageOptions/getDefaultInstance)
      (.getService)))

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

(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 []))))

hoopes03:02:02

still same 🙂 type hint the stuff in the (.create ...) call as well?

seancorfield03:02:33

Try (bytes byte-arr)

hoopes03:02:16

(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
             ^BlobInfo blob-info
             (bytes byte-arr)
             (into-array Storage$BlobTargetOption []))))

hoopes03:02:21

aaaaaaaaaand still same error

seancorfield03:02:41

You don't need the type hint on blob-info if you have the type hint on the function

hoopes03:02:51

yeah, i didn't think so, just grasping at straws a bit

seancorfield03:02:51

This works

user=> (import '(com.google.cloud.storage Storage))
com.google.cloud.storage.Storage
user=> (import '(com.google.cloud.storage BlobInfo))
com.google.cloud.storage.BlobInfo
user=> (import '(com.google.cloud.storage Storage$BlobTargetOption))
com.google.cloud.storage.Storage$BlobTargetOption
user=> (defn get-storage ^Storage [] nil)
#'user/get-storage
user=> (defn get-blob-info ^BlobInfo [] nil)
#'user/get-blob-info
user=> (.create (get-storage) (get-blob-info) (byte-array []) (into-array Storage$BlobTargetOption []))
Execution error (NullPointerException) at user/eval158 (REPL:1).
null

seancorfield03:02:10

(The NPE is from inside the call -- so it resolves the constructor just fine)

hoopes03:02:03

so you think the functions might be doing the wrong thing

seancorfield03:02:33

The only variable at this point is byte-arr -- so that needs to be the correct type.

hoopes03:02:42

dumb question:

hoopes03:02:44

user=> (def blob-info (storage/get-blob-info "bossjock-convert" "new-file.txt"))
#'user/blob-info
user=> blob-info
#object[com.google.cloud.storage.BlobInfo$BuilderImpl 0x3c690936 "com.google.cloud.storage.BlobInfo$BuilderImpl@3c690936"]

hoopes03:02:17

it's a BuilderImpl, not explicitly a BlobInfo - but that shouldn't matter to java - does it matter to clojure matching the function to a java method signature?

seancorfield03:02:40

That's why I used nil -- I'm trying to eliminate the values and focus on the type hints first.

seancorfield03:02:44

Since that works (for me), the possibilities are that your byte-arr is the wrong type (or needs a type hint).

seancorfield03:02:04

once you have the types working, you can look at the mechanics of your functions.

seancorfield03:02:47

I certainly would not expect a function that returns a BuildImpl to be compatible with a BlobInfo tho'... that seems wrong to me...

hoopes03:02:20

ok - i'm sorry, i have to handle real-life stuff for a bit

hoopes03:02:28

i really appreciate your help, and will continue working

hoopes03:02:38

if we ever meet, i owe you whatever drink you choose

seancorfield03:02:42

OK, your problem is calling .build inside doto -- that will return the builder instead of the built thing.

seancorfield03:02:19

You want (.build (doto (BlobInfo/newBuilder blob-id) (.setContentType content-type)))

hoopes03:02:53

that baby can wait! (jk jk jk jk)

hoopes03:02:50

ok, seriously, i have to attend to the baby - you are the man, and if we ever meet, it's a party

hoopes03:02:57

thanks man, you're a hero

seancorfield03:02:21

glad it worked