How to write efficiently constrained type code when types are not related in Scala

I want to improve on the following Scala code related to Cassandra. I have two unrelated custom types that are actually in Java source files (no details).

public class Blob { .. }
public class Meta { .. }

      

So, this is how I currently use them from Scala:

private val blobMapper: Mapper[Blob] = mappingManager.mapper(classOf[Blob])
private val metaMapper: Mapper[Meta] = mappingManager.mapper(classOf[Meta])

def save(entity: Object) = {
  entity match {
    case blob: Blob => blobMapper.saveAsync(blob)
    case meta: Meta => metaMapper.saveAsync(meta)
    case _ => // exception
 }
}

      

As long as this works, how can you avoid the following problems.

  • repetition when adding new user-defined classes such as Blob

    orMeta

  • Repeating pattern matching when adding new methods such as save

  • having Object

    as parameter type
+3


source to share


2 answers


You can definitely use Mapper

as a class by doing:

def save[A](entity: A)(implicit mapper: Mapper[A]) = mapper.saveAsync(entity)

      



You now have a generic method that can perform a save operation on every type A

for which "23" is in scope.

It is also possible that the implementation mappingManager.mapper

could be improved to avoid classOf

, but it is difficult to tell from the question in its current state.

+5


source


A few questions:

  • Is it mappingManager.mapper(cls)

    expensive?
  • How interested are you in handling Blob or Meta subclasses?

Could something like this work for you?

def save[T: Manifest](entity: T) = {
  mappingManager.mapper(manifest[T].runtimeClass).saveAsync(entity)
}

      



If you care about the Meta subclasses capturing the correct mapper, you may find it isAssignableFrom

helpful in your .mapper

(and store the subclasses found in a HashMap, so you only need to look once).

EDIT: Then maybe you want something like this (ignoring threading issues):

private[this] val mapperMap = mutable.HashMap[Class[_], Mapper[_]]()
def save[T: Manifest](entity: T) = {
  val cls = manifest[T].runtimeClass
  mapperMap.getOrElseUpdate(cls, mappingManager.mapper(cls))
    .asInstanceOf[Mapper[T]]
    .saveAsync(entity)
}

      

+1


source







All Articles