如何使用Scala的AnyVal调用Java varargs方法?

时间:2015-10-16 10:21:18

标签: java scala variadic-functions jooq

我有一个使用以下签名的Java方法(来自jOOQ):

Query query(String sql, Object... bindings);

现在,我想用AnyVal s在Scala中调用此方法,例如:

val id = 2
val value = 3.14
query(someString, id, value)

这样做会给我带来以下编译错误:

Error:(34, 16) overloaded method value query with alternatives:
  (x$1: String,x$2: org.jooq.QueryPart*)org.jooq.Query <and>
  (x$1: String,x$2: Object*)org.jooq.Query
 cannot be applied to (String, Int, Double)
        create.query(someString, id, lat)
               ^

然而,我可以明确地将每个AnyVal强制转换为AnyRef以强制执行自动装箱,从而消除编译器错误:

query(someString, id.asInstanceOf[AnyRef], value.asInstanceOf[AnyRef])

意识到这一点,我可以编写一个小函数,将所有对象强制转换为AnyRef,如下所示:

def toVarargs(arg: Any, args: Any*): Array[AnyRef] = {
    (arg +: args).map(_.asInstanceOf[AnyRef]).toArray
}

query(someString, toVarargs(id, value))

可悲的是,这不起作用,因为Array[AnyRef]被解释为单个varargs变量(将其更改为Array[Object]没有任何区别。)

可以使用_*运算符来完成此工作:

query(someString, toVarargs(id, value): _*)

然而,这似乎相当冗长。是否有一个更优雅的解决方案来解决这个问题,或者我将自己的功能与varargs运算符结合起来而陷入困境?

1 个答案:

答案 0 :(得分:2)

使用jOOQ 3.7,Conversions type of the jOOQ-scala extension中有一个新的SQLInterpolation类。它本质上只是:

implicit class SQLInterpolation(val sc : StringContext) extends AnyVal {

  def sql(args: Any*) : SQL = 
    DSL.sql(string, args.asInstanceOf[Seq[AnyRef]] : _*)

  def condition(args : Any*) : Condition = 
    DSL.condition(string, args.asInstanceOf[Seq[AnyRef]] : _*)

  def table(args : Any*) : Table[Record] = 
    DSL.table(string, args.asInstanceOf[Seq[AnyRef]] : _*)

  def query(args : Any*) : Query = 
    DSL.query(string, args.asInstanceOf[Seq[AnyRef]] : _*)

  def resultQuery(args : Any*) : ResultQuery[Record] = 
    DSL.resultQuery(string, args.asInstanceOf[Seq[AnyRef]] : _*)

  private def string = {
    val pi = sc.parts.iterator
    val sb = new StringBuilder(pi.next())
    var i = 0;

    while (pi.hasNext) {
      sb += '{'
      sb ++= (i toString)
      sb += '}'
      sb ++= pi.next()

      i = i + 1;
    }

    sb.result
  }
}

使用它,您应该能够写:

val id = 2
val value = 3.14
query"""SELECT * FROM t WHERE id = ${id} and value = ${value}"""

上述方法的优点在于它既可以使用上面的绑定值,也可以使用嵌入式SQL:

val id = 2
val value = 3.14
val condition = (MY_TABLE.ID === id) and (MY_TABLE.VALUE === value)
query"""SELECT * FROM t WHERE ${condition}"""