代码之家  ›  专栏  ›  技术社区  ›  Wolkenarchitekt

如何调用以泛型类型作为参数的映射的函数

  •  1
  • Wolkenarchitekt  · 技术社区  · 14 年前

    因此,我有一个Java元模型类(代码中只有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")
    

    现在我正在尝试创建一个查询函数,通过它我可以一次查询多个属性,因此我想使用一个属性映射作为我的函数的参数:

    // Map is of type scala.collection.immutable.Map
    def findByAttributes[T](
      attributes:Map[SingularAttribute[User, T], T]):ArrayList[User] = 
    {
      ...
    }
    

    好的,那么这个函数应该可以工作。。。但我怎么能叫它???例如,我想用这样的地图进行查询:

    User_.name -> "Doe"
    User_.id -> 5
    

    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]
    

    这是我遇到过的最复杂的问题。对我的技能来说有点太高了;)有人知道我如何构建可以传递给函数的正确映射类型吗?在我的例子中,编译器甚至不能推断出类型吗?还是我使用了错误的数据结构?

    2 回复  |  直到 14 年前
        1
  •  1
  •   Aaron Novstrup    14 年前

    我还没有完全弄清楚细节,但我认为

    type AttributeValuePair[T] = Pair[SingularAttribute[User, T], T]
    
    def findByAttributeValuePair[T](p:AttributeValuePair[T]):ArrayList[User] =
       findByAttribute(p._1, p._2)
    
    def findByAttributes(attributes:AttributeValuePair[_]*):ArrayList[User] = 
    {
       ...
    }
    

    findByAttributes(User_.name -> "Doe", User_.id -> 5)
    

    这个 findByAttributeValuePair findByAttribute

        2
  •  2
  •   Michel Krämer    14 年前

    当你宣布地图如下

    val criteria = Map(User_.name -> "Doe", User_.id -> 5)
    

    scala.collection.immutable.Map[SingularAttribute[User, _ >: Long with String], Any]
    

    在Scala的REPL中自己试一试!

    这里的问题是编译器推断 Any String Int 这是真的。所以,你失去了地图上实际值的信息。当然,关键也不是你想要什么。

    这意味着 Map 显然不是正确的类型。您可以尝试改用n元组:

    ((User_.name -> "Doe"), (User_.id -> 5))
    

    因此,所有类型信息都将正确存储。当然,您还需要创建几个 findByAttributes 函数(一个用于1元组,一个用于2元组,3元组等等…)。这有点乏味,但这是我现在能想到的最好的解决办法。