Clojure Can';t调用非公共类的public方法:public(谷歌云库)
我正试图使用图书馆Clojure Can';t调用非公共类的public方法:public(谷歌云库),clojure,gcloud,Clojure,Gcloud,我正试图使用图书馆 (ns firengine.state (:import [com.google.cloud AuthCredentials] [com.google.cloud.datastore DatastoreOptions])) (-> (DatastoreOptions/builder) (.projectId "<project_id>") (.authCredentials (AuthCredentia
(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 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
code
2016年6月29日更新:
根据下面的建议,我认为如果我围绕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}]))
我修改了我的启动开发任务
以包括以下内容:
(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
?是的。。。。这个问题。你不会相信的,但它实际上是来自。。。等等。。。1999!
你可以更多地了解它
为了避免这种情况,您可能必须制作自己的java包装器,或者考虑到这个众所周知的java bug
如果您不想编写自己的java包装器,并且作者坚持认为“这是最好的设计,就像有史以来一样!”,那么您可以通过使用(.setAccessible-method-true)
和一些更自定义的反射代码设置方法可访问性来强制实现
祝你好运 正如Shlomi所说,这是一个长期运行的bug。根据Noam Ben Ari关于clj jira的建议,我编写了一个小型java类来封装客户端创建,从而解决了这个问题。然后我可以直接从我的clj代码中使用它
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();
}
}
有关将Java编译添加到项目中的指导信息:
完全受此启发,我通过一个单独的示例来实现这一点。在中的src/gcloud/gcloudatastore.java
中创建了以下文件
因此,我是一个完全的Clojure noob,在使用咖啡因缓存时遇到了类似的错误:“IllegalArgumentException无法调用非公共类的公共方法:public default void com.github.benmanes.caffee.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)
)
即使这不是一个直接的答案,你的问题也超出了我的理解,我希望这能有所帮助
(defn get
[cache key]
(.getIfPresent cache key)
)
(defn get
[^Cache cache key]
(.getIfPresent cache key)
)