无法调用非公开类的公共方法:public(Google gcloud library)

时间:2016-06-27 17:36:41

标签: clojure gcloud

我正在尝试使用gcloud库。

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

上述clojure代码是从following code snippet翻译过来的(已省略,点击“Run others”)。

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

当我从Clojure REPL调用此代码时,出现以下错误。

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

com.google.cloud.datastore.DatastoreOptions代码can be found here

2016年6月29日更新: 根据{{​​3}}下面的建议,我想如果我AOT编译我自己的DatastoreOptions包装器它可能会起作用。

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

我修改了boot development任务以包含以下内容:

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

我试图像这样构建对象:

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

不幸的是,我仍然得到同样的错误?

    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)

我是不是真的没有编译firengine.datastore

4 个答案:

答案 0 :(得分:4)

是的......那个问题。你不会相信它,但它实际上是open bug in the jdk来自...等待它...... 1999年!

您可以在clojure jiragoogle groups上阅读更多内容。

您可能必须创建自己的java包装器以避免这种情况,或者ask the library author将这个旧的已知java错误考虑在内。

如果您不想编写自己的java包装器,并且作者坚持认为&#34;这是最好的设计,比如,永远!&#34;,那么您可以通过设置方法辅助功能来强制它(.setAccessible method true)以及更多自定义反射代码..

祝你好运!

答案 1 :(得分:1)

正如Shlomi所说,这是一个长期存在的错误。按照Noam Ben Ari关于clj-jira的建议,我通过编写一个包装客户端创建的小型java来管理问题。然后我可以直接从我的clj代码中使用它。

SELECT clientId 
FROM tblClientinformation 
WHERE taskID=21 
  AND FromDate <='7/29/2016' 
  AND ToDate >= '7/29/2016'; 

有关向项目添加Java编译的指导:

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

答案 2 :(得分:1)

所以,我是一个完整的Clojure noob并使用Caffeine Cache遇到了类似的错误:“IllegalArgumentException无法调用非公共类的公共方法:public default void com.github.benmanes.caffeine.cache.LocalManualCache。 put(java.lang.Object,java.lang.Object)clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:88)“

我的原始功能签名是这样的:

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

我认为问题是Clojure无法确定应用Cache的.getIfPresent函数的位置。添加类型固定它:

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

尽管这不是一个直接的答案而你的问题已经过去了,但我希望这会有所帮助。

答案 3 :(得分:0)

完全受到hironroy's answer的启发,我通过一个孤立的例子来解决这个问题。在the following github project中的src/gcloud/GcloduDatastore.java中创建了以下文件。

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

}