java 2019-02-25

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

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=> 

variadic is the ellipsis after the BlobTargetOption, ya?

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

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

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

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

Hmm, it has half a dozen overloads... no wonder it's tough to call šŸ˜ž

is that right? just pulled from the java interop page

this function call is looking funnier and funnier šŸ™‚

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

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

also tried with (bytes b)

I've seen people struggle with Google libraries because of this sort of stuff... ĀÆ\(惄)/ĀÆ

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

Sure. Definitely possible šŸ™‚

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

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).

does that make any sense?

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

What are s and b?

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

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

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

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

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

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

thanks so very much!

a hopefully more usable version:

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

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

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).

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

still same šŸ™‚ type hint the stuff in the (.create ...) call as well?

Try (bytes byte-arr)

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

aaaaaaaaaand still same error

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

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

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

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

so you think the functions might be doing the wrong thing

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

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

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?

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

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

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

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

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

i really appreciate your help, and will continue working

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

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

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

that baby can wait! (jk jk jk jk)

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

thanks man, you're a hero

glad it worked