babbitt
babbitt

Reputation: 901

Scala map method not behaving as expected

I'm new to Scala, so its probable that this is an incredibly obvious mistake. However, I'm trying to cast a List[Object] into List[A], where A is a parameter in the class.

class AbstractHibernateDAO[A<:Serializable]{
  def findAll: List[A] = {
    val objList = currentSession.createQuery("from " + clazz.getName()).list()
    objList.map{_.asInstanceOf[A]}
  }
}

Eclipse is puking up:

type mismatch;  found   : ?0(in method findAll) => A where type ?0(in method findAll)  required: (some other)?0(in method findAll) => ? where type (some other)?0(in method findAll)    AbstractHibernateDAO.scala  /springHibernateNoXML/src/main/scala/my/package

I've also tried the long form

objList.map{obj => obj.asInstanceOf[A]}

and get the same result.

Can anyone give me a hand?

[EDIT - Additional information]

For those that requested, here's the full listing:

package name.me


import java.io.Serializable
import java.util.List
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.context.annotation.Scope
import org.springframework.orm.hibernate3.HibernateTemplate
import org.springframework.stereotype.Repository
import com.google.common.base.Preconditions
import org.hibernate.SessionFactory
import org.hibernate.Session
import collection.JavaConversions._

@Repository
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
class AbstractHibernateDAO[A<:Serializable]{

  val clazz: Class[A] = null
  @Autowired val sessionFactory: SessionFactory = null

  def currentSession: Session = {
    sessionFactory getCurrentSession
  }

  def findOne(id: Long): A = {
    Preconditions checkArgument(id != null)
    currentSession.get(clazz, id).asInstanceOf[A]
  }

  def findAll: List[A] = {
    val objList = currentSession.createQuery("from " + clazz.getName()).list()
    objList.map(_.asInstanceOf[A])
    //This works
    //objList.asInstanceOf[List[A]]
  }

  def save(entity:A){
    Preconditions checkNotNull entity
    currentSession persist entity
  }

  def update(entity: A){
    Preconditions checkNotNull entity
    currentSession merge entity
  }

  def delete(entity: A){
    Preconditions checkNotNull entity
    currentSession delete entity
  }

  def deleteById(entityId: Long){
    Preconditions checkNotNull entityId
    val entity = findOne(entityId) 
    Preconditions checkNotNull entity
    delete(entity)
  }
}

Upvotes: 2

Views: 322

Answers (2)

Luigi Plinge
Luigi Plinge

Reputation: 51109

A quick look at the Hibernate API docs shows that Query.list() returns a java.util.List, but you have a type annotation of List[A], which is by default (from the scala package object) a scala.collection.immutable.List.

Which do you want to return?

for Java List, change your type annotation and cast the whole list:

class AbstractHibernateDAO[A<:Serializable]{
  def findAll: java.util.List[A] = {
    val objList = currentSession.createQuery("from " + clazz.getName()).list()
    objList.asInstanceOf[java.util.List[A]]
  }
}

for Scala List, use JavaConversions:

class AbstractHibernateDAO[A<:Serializable]{
  def findAll: List[A] = {
    val objList = currentSession.createQuery("from " + clazz.getName()).list()
    import collection.JavaConversions._
    objList.toList.asInstanceOf[List[A]]
  }
}

Upvotes: 2

dhg
dhg

Reputation: 52701

Are you sure of the type of objList? Is it really a scala.collection.immutable.List of java.util.Object? You can check this easily by adding a type to your variable declaration:

val objList: List[java.util.Object] = ...

Assuming that's correct, your code seems fine. But I can't run it without having all the other code. I can do what you are trying with a simplified example:

def convertAll[A](data: List[java.lang.Object]): List[A] =
  data.map(_.asInstanceOf[A])

convertAll[java.lang.Integer](List(1,2).map(new java.lang.Integer(_)))
// List[java.lang.Integer] = List(1, 2)

However, you shouldn't need to cast each item in the List. Try just casting the list to its new type:

objList.asInstanceOf[List[A]]

For example:

val x: List[java.lang.Object] = List(1,2).map(new java.lang.Integer(_))
x.asInstanceOf[List[java.lang.Integer]]
// List[java.lang.Integer] = List(1, 2)

Upvotes: 3

Related Questions