2016-06-27 9 views
3

Ich versuche, die gcloud-Bibliothek zu verwenden.Öffentliche Methode der nicht öffentlichen Klasse kann nicht aufgerufen werden: public (Google gcloud-Bibliothek)

(ns firengine.state 
    (:import 
    [com.google.cloud AuthCredentials] 
    [com.google.cloud.datastore DatastoreOptions])) 

(-> (DatastoreOptions/builder) 
     (.projectId "<project_id>") 
     (.authCredentials 
     (AuthCredentials/createForJson 
     (clojure.java.io/input-stream service-account-path))) 
     .build) 

Die obige clojure Code aus dem following code snippet (ellided, klicken Sie auf "Ausführen anderer Stelle") übersetzt wird.

import com.google.cloud.AuthCredentials; 
import com.google.cloud.datastore.DatastoreOptions; 

DatastoreOptions options = DatastoreOptions.builder() 
    .projectId(PROJECT_ID) 
    .authCredentials(AuthCredentials.createForJson(
    new FileInputStream(PATH_TO_JSON_KEY))).build(); 

Wenn ich diesen Code von der Clojure REPL aufrufen, erhalte ich den folgenden Fehler.

Unhandled java.lang.IllegalArgumentException 
    Can't call public method of non-public class: public 
    com.google.cloud.ServiceOptions$Builder 
    com.google.cloud.ServiceOptions$Builder.projectId(java.lang.String) 

      Reflector.java: 88 clojure.lang.Reflector/invokeMatchingMethod 
      Reflector.java: 28 clojure.lang.Reflector/invokeInstanceMethod 
boot.user4590132375374459695.clj: 168 firengine.state/eval17529 
boot.user4590132375374459695.clj: 167 firengine.state/eval17529 
      Compiler.java: 6927 clojure.lang.Compiler/eval 
           ... elided ... 

Der com.google.cloud.datastore.DatastoreOptions Code can be found here.

29. Juni aktualisiert, 2016: Nach Beratung unten an Schlomi ‚s, dachte ich, dass vielleicht, wenn ich meine eigenen Wrapper um kompiliert AOT DatastoreOptions, dass es funktionieren würde.

(ns firengine.datastore 
    (:import 
    [com.google.cloud AuthCredentials] 
    [com.google.cloud.datastore Datastore DatastoreOptions Entity Key KeyFactory]) 
    (:gen-class 
    :state state 
    :init init 
    :constructors {[String String] []})) 

(defn -init 
    [^String project-id ^String service-account-path] 
    (let [service-account (clojure.java.io/input-stream service-account-path) 
     credentials (AuthCredentials/createForJson service-account) 
     dsoptions (-> (DatastoreOptions/builder) 
         (.projectId project-id) 
         (.authCredentials credentials) 
         .build)] 
     [[] {:project-id project-id 
       :service-account-path service-account-path 
       :datastore-options dsoptions}])) 

Ich veränderte mein boot development Aufgabe, schließen Folgendes ein:

(deftask development 
    "Launch Immediate Feedback Development Environment" 
    [] 
    (comp 
    (aot :namespace '#{firengine.datastore}) 
    (repl :port 6800) 
    (reload) 
    (watch) 
    (cljs) 
    (target :dir #{"target"}))) 

Und ich wie so um das Objekt zu konstruieren versucht:

(def service-account-path (System/getenv "FIRENGINE_SERVICE_ACCOUNT_PATH")) 

(def project-id (System/getenv "PROJECT_ID")) 

(def datastore-options (firengine.datastore. project-id service-account-path)) 

Leider habe ich immer noch die gleichen Fehler?

clojure.lang.Compiler$CompilerException: java.lang.reflect.InvocationTargetException, compiling:(state.clj:15:1) 
java.lang.reflect.InvocationTargetException: 
     java.lang.IllegalArgumentException: Can't call public method of non-public class: public com.google.cloud.ServiceOptions$Builder com.google.cloud.ServiceOptions$Builder.projectId(java.lang.String) 

Bin ich nicht wirklich aot kompilieren firengine.datastore?

Antwort

4

Ja .... dieses Problem. Sie würden es nicht glauben, aber es ist eigentlich ein open bug in the jdk von ... warten Sie darauf ... 1999!

Sie können darüber in clojure jira und auf googlegroups lesen.

Sie müssen möglicherweise Ihren eigenen Java-Wrapper erstellen, um dies zu vermeiden, oder ask the library author, um diesen alten bekannten Java-Fehler in Betracht zu ziehen.

Wenn Sie nicht Ihren eigenen Java-Wrapper schreiben möchten, und der Autor darauf besteht, dass "das ist das beste Design, wie immer!", Dann könnten Sie immer erzwingen, indem Sie die Methode Barrierefreiheit mit (.setAccessible method true) und einige benutzerdefinierte Reflexionscode ..

Viel Glück!

1

Wie Shlomi sagte, das ist ein lang laufender Bug. Nach dem Rat von Noam Ben Ari auf der Clj-Jira, habe ich es geschafft, das Problem zu umgehen, indem ich eine kleine Java-Klasse schreibe, die die Client-Erstellung umschließt. Ich kann das dann direkt aus meinem clj-Code verwenden.

package pubsub_echo.pubsub; 

import com.google.cloud.AuthCredentials; 
import com.google.cloud.pubsub.PubSub; 

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 

public class GCloudPubSub { 

    public PubSub getClient() throws FileNotFoundException, IOException { 
     PubSubOptions.Builder optionsBuilder = PubSubOptions.builder(); 
     ClassLoader classLoader = getClass().getClassLoader(); 
     FileInputStream authStream = new FileInputStream(classLoader.getResource("SERVICE_ACCOUNT.json").getPath()); 
     AuthCredentials creds = AuthCredentials.createForJson(authStream); 

     return optionsBuilder 
      .authCredentials(creds) 
      .projectId("PROJECT_ID") 
      .build() 
      .service(); 
    } 

} 

Für Hinweise zur Java-Kompilierung zu einem Projekt hinzu:

https://github.com/technomancy/leiningen/blob/master/doc/MIXED_PROJECTS.md

0

Völlig von hironroy's answer inspiriert, arbeitete ich durch ein isoliertes Beispiel für diese Arbeit zu bekommen. Erstellt die Datei unten in src/gcloud/GcloduDatastore.java in the following github project.

package gcloud; 

import com.google.cloud.AuthCredentials; 
import com.google.cloud.datastore.Datastore; 
import com.google.cloud.datastore.DatastoreOptions; 
import com.google.cloud.datastore.DatastoreOptions.Builder; 

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 

public class GCloudDatastore { 

    public static Datastore getDatastore() throws FileNotFoundException, IOException { 
     DatastoreOptions.Builder optionsBuilder = DatastoreOptions.builder(); 
     FileInputStream authStream = new FileInputStream(System.getenv("SERVICE_ACCOUNT_DOT_JSON_PATH")); 
     AuthCredentials creds = AuthCredentials.createForJson(authStream); 

     return optionsBuilder 
      .authCredentials(creds) 
      .projectId(System.getenv("PROJECT_ID")) 
      .build() 
      .service(); 
    } 

} 
1

so, ich bin ein absoluter Noob Clojure und lief in einen ähnlichen Fehler mit Koffein Cache: „Illegal nicht öffentliche Methode der nicht-öffentlichen Klasse aufrufen können: public Standard Leere com.github.benmanes.caffeine. cache.LocalManualCache.put (java.lang.Object, java.lang.Object) clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:88)“

meine ursprüngliche Funktion Unterschrift lautete:

(defn get 
    [cache key] 
    (.getIfPresent cache key) 
) 

und ich denke, das Problem ist, dass Clojure konnte nicht herausfinden, wo zu applizieren y. Die Funktion .getIfPresent des Cache. Das Hinzufügen der Typ es fest:

(defn get 
    [^Cache cache key] 
    (.getIfPresent cache key) 
) 

Auch wenn es keine direkte Antwort und Ihre Frage ging über meinen Kopf, ich hoffe, das hilft.