84

I am trying to create a generic method for object updates using scala / java but I can't get the class for a type parameter.

Here is my code:

object WorkUnitController extends Controller {     
 def updateObject[T](toUpdate: T, body: JsonObject){
  val source = gson.fromJson(body, classOf[T]);
  ...
 }
}

The error i get is

class type required but T found

I know in java you can't do it but is this possible in scala at all?

Thanks!

mericano1
  • 2,914
  • 1
  • 18
  • 25
  • See also: https://issues.scala-lang.org/browse/SI-5722 – soc Aug 15 '13 at 15:34
  • You can simply do it in Java in this way: ```public void updateObject(T toUpdate, JsonObject body) { gson.fromJson(body, toUpdate.getClass()); }``` – MHM Jun 27 '22 at 06:39

2 Answers2

99

Due Manifest is deprecated (Since Scala 2.10.0) this is the updated answer -

import scala.reflect.ClassTag
import scala.reflect._

object WorkUnitController extends Controller {
  def updateObject[T: ClassTag](toUpdate: T, body: JsonObject){
    val source = gson.fromJson(body, classTag[T].runtimeClass)
    ???
  }
}

You should use ClassTag instead of ClassManifest and .runtimeClass instead of .erasure

Original answer - Yes, you can do that using manifests:

object WorkUnitController extends Controller {     
 def updateObject[T: ClassManifest](toUpdate: T, body: JsonObject){
  val source = gson.fromJson(body, classManifest[T].erasure);
  ...
 }
}
Maxim
  • 7,268
  • 1
  • 32
  • 44
Vasil Remeniuk
  • 20,519
  • 6
  • 71
  • 81
  • Oh god that's amazing! I wish I'd known about this earlier! – Darkzaelus Jun 01 '11 at 11:22
  • I was reading about manifests that "Starting with version 2.7.2, Scala has added manifests, an undocumented (and still experimental) feature" I'm using scala 2.8 do you know if it is still experimental? – mericano1 Jun 01 '11 at 11:30
  • 1
    You can even write `manifest[T]` instead of `implicitly[Manifest[T]]`. – Jean-Philippe Pellet Jun 01 '11 at 11:31
  • 1
    @mericano1 they've become an essential part of the language, and, I think, Manifests are no longer an experimental feature – Vasil Remeniuk Jun 01 '11 at 11:37
  • @mericano1 Manifests are still subject to change, but `ClassManifest` is required for handling generic array instantiation, faster than `Manifest`, and support `erasure` just as well. – Daniel C. Sobral Jun 01 '11 at 14:42
  • Could you update your answer with an example call to updateObject()? I'm struggling to figure out the right types for the call – Alex Dean Aug 02 '11 at 07:29
  • You should be able to call it right away, passing just 2 parameters. Manifest will be provided implicitly, w/o any effort from your side. – Vasil Remeniuk Aug 02 '11 at 09:53
  • @Alex will be smth like this -> `WorkUnitController.updateObject(yourTypedObject, body)` – Vasil Remeniuk Aug 02 '11 at 09:56
  • 12
    @mericano1 One update: `Manifest` and `ClassManifest` are now deprecated, having been replaced with `TypeTag` and `ClassTag`, respectively, on Scala 2.10. – Daniel C. Sobral Jun 15 '12 at 13:48
  • @DanielC.Sobral `TypeTag`s are not production ready. Unfortunately at this moment Scala runtime reflection is completely unstable. – ghik Jun 06 '13 at 21:04
  • I'm having trouble with this solution using 2.10.1. Given the comment about deprecation I tried something like this: def thaw[T:ClassTag]( js:String )(implicit mapper:ObjectMapper) : T = { mapper.readValue(js, ClassTag[T]) // orig. needs readValue(js, classOf[T]) } This give me an error. Any ideas? Thanks, Greg – Greg Jun 07 '13 at 00:22
  • @Greg What error? This is not topic for comments -- ask a question. – Daniel C. Sobral Jun 07 '13 at 14:25
  • @Greg you need to use `classTag[T].runtimeClass` instead of `classOf[T]` when using `ClassTag`s. – cdmckay Jul 10 '13 at 00:46
  • Just updted the answer to classTag – dirceusemighini Oct 28 '14 at 17:16
  • 16
    Instead of `classTag[T].runtimeClass` I needed `classTag[T].runtimeClass.asInstanceOf[Class[T]]`. Does anybody know why? – mutantacule Dec 09 '14 at 09:16
  • 1
    Would be interesting to get the answer. Basically what is the difference between Class[_] and Class[T] at run-time or compile time. – user-asterix Jul 03 '17 at 17:04
10

Vasil's and Maxim's answer helped me.

Personally, I prefer the syntax where implicit is used for adding such parameters (the presented : ClassTag is shorthand for it. So here, in case someone else also sees this to be a better way:

import scala.reflect.ClassTag

object WorkUnitController extends Controller {
  def updateObject[T](toUpdate: T, body: JsonObject)(implicit tag: ClassTag[T]){
    val source = gson.fromJson(body, tag.runtimeClass)
    ???
  }
}

Demonstration: https://scastie.scala-lang.org/Vij5rpHNRDCPPG1WHo566g

ecoe
  • 4,994
  • 7
  • 54
  • 72
akauppi
  • 17,018
  • 15
  • 95
  • 120