如何调用具有通用类型作为参数的映射的函数
我正在使用 Scala 执行类型安全的 JPA2 标准查询。 因此,我有一个 Java MetaModel 类(我的代码中唯一的 Java,其余的是 Scala -> 纯 Scala 问题),它保存我的模型属性:
@StaticMetamodel(User.class)
public class User_ {
public static volatile SingularAttribute<User, Long> id;
public static volatile SingularAttribute<User, String> name;
}
要查询一个属性,我有这个函数:
def findByAttribute[T](
attribute:SingularAttribute[User, T], value:T):ArrayList[User] =
{
...
}
我可以像这样调用:
userEJB.findByAttribute(User_.name, "John")
现在我正在尝试创建一个查询函数,用它我可以一次查询多个属性,因此我想使用 SingularAttributes 的 Map 作为我的函数的参数:
// Map is of type scala.collection.immutable.Map
def findByAttributes[T](
attributes:Map[SingularAttribute[User, T], T]):ArrayList[User] =
{
...
}
好的,所以该函数应该可以工作...但是我该怎么称呼它呢?举例来说,我想使用这样的 Map 进行查询:
User_.name -> "Doe"
User_.id -> 5
因此,我在 Scala 中定义此 Map 并将其传递给 findByAttributes 的第一种方法是这样的:
val criteria = Map(User_.name -> "Doe", User_.id -> 5)
// Produces Compiler Error
val users = userEJB.findByAttributes(criteria)
不幸的是,编译器在将 searchFor 传递给 findByAttributes 函数时不满意,产生了下面的错误:
no type parameters for method findByAttributes: (attributes:
Map[javax.persistence.metamodel.SingularAttribute[net.teachernews.model.User,
T],T])
java.util.ArrayList[net.teachernews.model.User] exist so that it can be applied to
arguments (scala.collection.immutable.Map[javax.persistence.metamodel.
SingularAttribute[
net.teachernews.model.User, _
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_ >: java.lang.Long with java.lang.String
<: java.io.Serializable] with java.io.Serializable]
with java.io.Serializable],Any]) --- because ---
argument expression's type is not compatible with formal parameter type;
found :
scala.collection.immutable.Map[javax.persistence.metamodel.SingularAttribute[
net.teachernews.model.User, _
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_ >: java.lang.Long with java.lang.String
<: java.io.Serializable] with java.io.Serializable] with java.io.Serializable],
Any]
required: Map[javax.persistence.metamodel.SingularAttribute[
net.teachernews.model.User,?T],?T]
这是我遇到过的最复杂的一般问题。对于我的技能来说有点太高了;)有人知道我如何构建可以传递给函数的正确地图类型吗?是否有可能,或者编译器在我的情况下不能再推断类型?或者我使用了错误的数据结构?
I'm using Scala to do typesafe JPA2 Criteria Queries.
Therefore i have a Java MetaModel Class (the only Java in my code, the rest is Scala -> pure Scala problem), which holds my model attributes:
@StaticMetamodel(User.class)
public class User_ {
public static volatile SingularAttribute<User, Long> id;
public static volatile SingularAttribute<User, String> name;
}
To do a query for one single attribute, i have this function:
def findByAttribute[T](
attribute:SingularAttribute[User, T], value:T):ArrayList[User] =
{
...
}
Which i can call like this:
userEJB.findByAttribute(User_.name, "John")
Now i'm trying to create a query function, with which i can query for multiple attributes at once, and therefore i want to use a Map of SingularAttributes as a parameter for my function:
// Map is of type scala.collection.immutable.Map
def findByAttributes[T](
attributes:Map[SingularAttribute[User, T], T]):ArrayList[User] =
{
...
}
Ok, so the function should work... But how can i call it??? Say for example i want to query with a Map like this:
User_.name -> "Doe"
User_.id -> 5
So my first approach of defining this Map in Scala and passing it to findByAttributes is this:
val criteria = Map(User_.name -> "Doe", User_.id -> 5)
// Produces Compiler Error
val users = userEJB.findByAttributes(criteria)
Unfortunately, the compiler isn't satisfied when passing searchFor to the findByAttributes-function, producing the error below:
no type parameters for method findByAttributes: (attributes:
Map[javax.persistence.metamodel.SingularAttribute[net.teachernews.model.User,
T],T])
java.util.ArrayList[net.teachernews.model.User] exist so that it can be applied to
arguments (scala.collection.immutable.Map[javax.persistence.metamodel.
SingularAttribute[
net.teachernews.model.User, _
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_ >: java.lang.Long with java.lang.String
<: java.io.Serializable] with java.io.Serializable]
with java.io.Serializable],Any]) --- because ---
argument expression's type is not compatible with formal parameter type;
found :
scala.collection.immutable.Map[javax.persistence.metamodel.SingularAttribute[
net.teachernews.model.User, _
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_
>: java.lang.Long with java.lang.String
<: java.lang.Comparable[_ >: java.lang.Long with java.lang.String
<: java.io.Serializable] with java.io.Serializable] with java.io.Serializable],
Any]
required: Map[javax.persistence.metamodel.SingularAttribute[
net.teachernews.model.User,?T],?T]
That's the most complicated generic problem i ever had. A bit too high for my skill ;) Anyone knows how i can build the right map type that i can pass to the function? Is it even possible, or can't the compiler infer the type anymore in my case? Or am i using the wrong datastructure?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
当您按如下方式声明映射时,
编译器将推断出一个有点奇怪的类型:
在 Scala 的 REPL 中亲自尝试一下!
这里的问题是编译器将
Any
推断为String
和Int
的常见类型,这实际上是正确的。因此,您将丢失有关地图中实际值的任何信息。当然,关键也不是您真正想要的。这意味着
Map
显然不是正确的类型。您可以尝试使用 n 元组:因此,所有类型信息都将被正确存储。当然,您随后必须创建多个
findByAttributes
函数(一个用于 1 元组,一个用于 2 元组、3 元组,依此类推...)。这有点乏味,但这是我现在能想到的最好的解决方案。When you declare the map as follows
the compiler will infer a somewhat weird type:
Try it out yourself in Scala's REPL!
The problem here is that the compiler infers
Any
as the common type ofString
andInt
which is actually true. So, you're losing any information about the actual values in the map. And of course the key also isn't really what you would want.This means that
Map
is obviously not the right type. You could try to use a n-tuple instead:So, all type information will be stored correctly. Of course, you will then have to create several
findByAttributes
functions (one for 1-tuple, one for 2-tuple, 3-tuple and so on ...). This is a bit tedious, but it's the best solution I could think of now.我还没有完全弄清楚细节,但我认为类似的东西
可能会起作用。然后,调用看起来像
Edit: 从我的摆弄来看,可能需要
findByAttributeValuePair
方法来调用findByAttribute
进行类型检查在 Scala 2.8 REPL 中。I haven't fully worked out the details, but I think something like
might work. Then a call would look like
Edit: The
findByAttributeValuePair
method may be necessary to get the call tofindByAttribute
to type-check, judging from my fiddling in the Scala 2.8 REPL.