【问题标题】:No matching method found with JDBI and Clojure找不到与 JDBI 和 Clojure 匹配的方法
【发布时间】:2017-12-01 13:56:30
【问题描述】:

我有一个简单的 DAO ns:

(ns   alavita.dao
  (:require
    [clojure.tools.logging    :as     log     ]
    [clojure.java.io          :as     io      ]
  )
  (:import
    [org.jdbi.v3.core Jdbi Handle]
  ))

(defn create
  (^Jdbi [^String url]
    (Jdbi/create url))
  (^Jdbi [^String url ^String username ^String password]
    (Jdbi/create url username password)))

(defn open
  ^Handle [^Jdbi jdbi]
  (.open jdbi))

尝试使用库时:

alavita.core=> (def c (dao/create "jdbc:sqlite:/tmp/data.db"))
#'alavita.core/c
alavita.core=> (def h (dao/open c))
#'alavita.core/h
alavita.core=> (.execute h "show tables")

IllegalArgumentException No matching method found: execute for class org.jdbi.v3.core.Handle  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)

这有点奇怪,因为 h 肯定有 .execute:

alavita.core=> (cli/all-methods h)
(.attach .begin .close .commit .createBatch .createCall .createQuery .createScript .createUpdate .execute .getConfig .getConnection .getExtensionMethod .getStatementBuilder .getTransactionIsolationLevel .inTransaction .isClosed .isInTransaction .isReadOnly .lambda$attach$3 .lambda$new$0 .lambda$useTransaction$1 .lambda$useTransaction$2 .prepareBatch .release .rollback .rollbackToSavepoint .savepoint .select .setConfig .setConfigThreadLocal .setExtensionMethod .setExtensionMethodThreadLocal .setReadOnly .setStatementBuilder .setTransactionIsolation .useTransaction)

不确定它会横向移动。

打开和创建的类型:

alavita.core=> (type (dao/create "jdbc:sqlite:/tmp/data.db"))
org.jdbi.v3.core.Jdbi
alavita.core=> (type (dao/open c))
org.jdbi.v3.core.Handle

添加反射:

alavita.core=> (set! *warn-on-reflection* true)
true
alavita.core=> (.execute h "show tables")
Reflection warning, /private/var/folders/nr/g50ld9t91c555dzv91n43bg40000gn/T/form-init767780595230125901.clj:1:1 - call to method execute can't be resolved (target class is unknown).

IllegalArgumentException No matching method found: execute for class org.jdbi.v3.core.Handle  clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:53)

【问题讨论】:

  • 您的类型提示说open 接受一个Jdbi,并返回一个句柄,但错误和它诉诸反射的事实表明jdbi 已经一个手柄。错误提到open,而不是.exexute
  • 验证 Jdbi/create 返回的内容。
  • 嗯,从未使用过该 API,但查看文档后您的用法似乎正确。我会在open 中进行一些前/后类型检查。
  • @Carcigenicate 你说得对,我复制粘贴失败。实际上是执行它有问题。我修好了。
  • 啊,我知道这是什么。这是因为 execute 使用 var args。让我们看看我是否记得如何解决这个问题...

标签: clojure jdbi


【解决方案1】:

正如this port 中提到的,这是Java 如何处理var-args 的问题。您需要先将 var-args 包装在一个数组中,而不是依赖于 var-arg 行为。

我建议编写一个 Clojure 函数来处理这个问题:

(defn execute [^Handle h, ^String sql, & args]
  (.execute h sql (into-array Object args)))

并改用它。

【讨论】:

  • 有趣的是我只是把它击退了。(.execute h "show tables" (into-array []))
  • 我在使用这个解决方案时遇到了这个问题:(into-array ["/tmp" 0]) IllegalArgumentException array element type mismatch java.lang.reflect.Array.set (Array.java:- 2)
  • @Istvan 你确定要将字符串和整数放在同一个数组中吗?
  • 您还能如何将整数和文本字段插入到表格中?
  • @Istvan 如果这就是你想要的,试试(into-array Object ["/temp" 0])。如果元素类型不同,则需要指定基类。
猜你喜欢
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多