I am seeing some strange (un)boxing behaviour in Scala I cannot explain.
Consider the following code:
case class SomeCaseClass(longOpt: Option[Long])
def someMethod(l: Long): Unit = ???
val x: SomeCaseClass = // Case class populated from JSON in some code I do not control
x.longOpt.map(l => someMethod(l))
The attempt to call someMethod yields the following error:
java.lang.ClassCastException java.lang.Integer cannot be cast to java.lang.Long
at scala.runtime.BoxesRuntime.unboxToLong(BoxesRuntime: 105)
Running the following:
x.longOpt.map(_.getClass).get
yields long
Obviously the conversion of JSON to the case class is the prime suspect but I would expect a runtime error instantiating the case class if the value was not of the correct type.
Can anyone explain what is happening here?
Obviously the conversion of JSON to the case class is the prime suspect but I would expect a runtime error instantiating the case class if the value was not of the correct type.
I want to understand why Scala does not complain when the case class is created, only when I attempt to manipulate the Option[Long] which it would appear does not contain a Long at all...
I guess the thing is in type erasure. For
case class SomeCaseClass(longOpt: Option[Long])
Option[Long] is just Option[_] at runtime. So there is no ClassCastException during instantiating the case class because it's not casting Option[Integer] to Option[Long], it's Option[_] to Option[_].
And when you work with the content of Option it's ClassCastException because you try to cast Integer to Long.
Related
I'm trying to construct a trait and an abstract class to subtype by messages (In an Akka play environment) so I can easily convert them to Json.
What have done so far:
abstract class OutputMessage(val companion: OutputMessageCompanion[OutputMessage]) {
def toJson: JsValue = Json.toJson(this)(companion.fmt)
}
trait OutputMessageCompanion[OT] {
implicit val fmt: OFormat[OT]
}
Problem is, when I'm trying to implement the mentioned interfaces as follows:
case class NotifyTableChange(tableStatus: BizTable) extends OutputMessage(NotifyTableChange)
object NotifyTableChange extends OutputMessageCompanion[NotifyTableChange] {
override implicit val fmt: OFormat[NotifyTableChange] = Json.format[NotifyTableChange]
}
I get this error from Intellij:
Type mismatch, expected: OutputMessageCompanion[OutputMessage], actual: NotifyTableChange.type
I'm kinda new to Scala generics - so help with some explanations would be much appreciated.
P.S I'm open for any more generic solutions than the one mentioned.
The goal is, when getting any subtype of OutputMessage - to easily convert it to Json.
The compiler says that your companion is defined over the OutputMessage as the generic parameter rather than some specific subtype. To work this around you want to use a trick known as F-bound generic. Also I don't like the idea of storing that companion object as a val in each message (after all you don't want it serialized, do you?). Defining it as a def is IMHO much better trade-off. The code would go like this (companions stays the same):
abstract class OutputMessage[M <: OutputMessage[M]]() {
self: M => // required to match Json.toJson signature
protected def companion: OutputMessageCompanion[M]
def toJson: JsValue = Json.toJson(this)(companion.fmt)
}
case class NotifyTableChange(tableStatus: BizTable) extends OutputMessage[NotifyTableChange] {
override protected def companion: OutputMessageCompanion[NotifyTableChange] = NotifyTableChange
}
You may also see standard Scala collections for an implementation of the same approach.
But if all you need the companion for is to encode with JSON format, you can get rid of it like this:
abstract class OutputMessage[M <: OutputMessage[M]]() {
self: M => // required to match Json.toJson signature
implicit protected def fmt: OFormat[M]
def toJson: JsValue = Json.toJson(this)
}
case class NotifyTableChange(tableStatus: BizTable) extends OutputMessage[NotifyTableChange] {
override implicit protected def fmt: OFormat[NotifyTableChange] = Json.format[NotifyTableChange]
}
Obviously is you also want to decode from JSON you still need a companion object anyway.
Answers to the comments
Referring the companion through a def - means that is a "method", thus defined once for all the instances of the subtype (and doesn't gets serialized)?
Everything you declare with val gets a field stored in the object (instance of the class). By default serializers trying to serialize all the fields. Usually there is some way to say that some fields should be ignored (like some #IgnoreAnnotation). Also it means that you'll have one more pointer/reference in each object which uses memory for no good reason, this might or might not be an issue for you. Declaring it as def gets a method so you can have just one object stored in some "static" place like companion object or build it on demand every time.
I'm kinda new to Scala, and I've peeked up the habit to put the format inside the companion object, would you recommend/refer to some source, about how to decide where is best to put your methods?
Scala is an unusual language and there is no direct mapping the covers all the use cases of the object concept in other languages. As a first rule of thumb there are two main usages for object:
Something where you would use static in other languages, i.e. a container for static methods, constants and static variables (although variables are discouraged, especially static in Scala)
Implementation of the singleton pattern.
By f-bound generic - do you mean the lower bound of the M being OutputMessage[M] (btw why is it ok using M twice in the same expr. ?)
Unfortunately wiki provides only a basic description. The whole idea of the F-bounded polymorphism is to be able to access to the type of the sub-class in the type of a base class in some generic manner. Usually A <: B constraint means that A should be a subtype of B. Here with M <: OutputMessage[M], it means that M should be a sub-type of the OutputMessage[M] which can easily be satisfied only by declaring the child class (there are other non-easy ways to satisfy that) as:
class Child extends OutputMessage[Child}
Such trick allows you to use the M as a an argument or result type in methods.
I'm a bit puzzled about the self bit ...
Lastly the self bit is another trick that is necessary because F-bounded polymorphism was not enough in this particular case. Usually it is used with trait when traits are used as a mix-in. In such case you might want to restrict in what classes the trait can be mixed in. And at the same type it allows you to use the methods from that base type in your mixin trait.
I'd say that the particular usage in my answer is a bit unconventional but it has the same twofold effect:
When compiling OutputMessage the compiler can assume that the type will also somehow be of the type of M (whatever M is)
When compiling any sub-type compiler ensures that the constraint #1 is satisfied. For example it will not let you to do
case class SomeChild(i: Int) extends OutputMessage[SomeChild]
// this will fail because passing SomeChild breaks the restriction of self:M
case class AnotherChild(i: Int) extends OutputMessage[SomeChild]
Actually since I had to use self:M anyway, you probably can remove the F-bounded part here, living just
abstract class OutputMessage[M]() {
self: M =>
...
}
but I'd stay with it to better convey the meaning.
As SergGr already answered, you would need an F-Bounded kind of polymorphism to solve this as it is right now.
However, for these cases, I believe (note this is only my opinion) is better to use Typeclasses instead.
In your case, you only want to provide a toJson method to any value as long as they have an instance of the OFormat[T] class.
You can achieve that with this (more simple IMHO) piece of code.
object syntax {
object json {
implicit class JsonOps[T](val t: T) extends AnyVal {
def toJson(implicit: fmt: OFormat[T]): JsVal = Json.toJson(t)(fmt)
}
}
}
final case class NotifyTableChange(tableStatus: BizTable)
object NotifyTableChange {
implicit val fmt: OFormat[NotifyTableChange] = Json.format[NotifyTableChange]
}
import syntax.json._
val m = NotifyTableChange(tableStatus = ???)
val mJson = m.toJson // This works!
The JsonOps class is an Implicit Class which will provide the toJson method to any value for which there is an implicit OFormat instance in scope.
And since the companion object of the NotifyTableChange class defines such implicit, it is always in scope - more information about where does scala look for implicits in this link.
Additionally, given it is a Value Class, this extension method does not require any instantiation in runtime.
Here, you can find a more detailed discussion about F-Bounded vs Typeclasses.
I am using an external service and I am expecting to receive a json containing a field with three kinds of value:
A Double
null
The field could be absent
I need to deserialize the json into a case class and somewhere else in the code I need to serialize it to a json with the same fields.
I have an implicit reads and write:
implicit lazy val aReads: Reads[A] = (
"foo".readNullable[Double]
)(A.apply _)
implicit lazy aWrites: OWrites[A] = (
"foo".write[Option[Double]]
)
and the case class:
case class A(
foo: Option[Double]
)
As you can imagine the problem is that I am not able to "catch" when the value is absent and if a use "foo".writeNullable[Double] as writers I am not able to catch when it's null (it will be always absent). How can I solve this issue?
What you need is actually a data type which reflects three states:
Present
Null
Non Existing
There is actually a nice encoding of this here, which is semantically equivalent to:
sealed trait Tristate[+A]
case class Present[+A](a: A) extends Tristate[A]
case object Absent extends Tristate[Nothing] // this can represent your "null" state
case object NonExisting extends Tristate[Nothing]
The small library linked has nice combinators over Tristate such as map, flatMap, filter, etc.
And then, you can derive a Play decoder/encoder which puts the object in the correct state serializes appropriately.
I am trying to build a generic CRUD interface that receives an element, searches for an implicit CRUD implementation from an evidence and also serialize the necessary object based on the parametrized type.
The code goes as follow:
private def createElement[T <: AnyRef](element: String)
(implicit ev: ResourceManager[T], m: Manifest[T]): Response = Try {
val e = Serializer.fromJson(element, m.runtimeClass)
ev.create(e, persistence)
ResponseBuilder.newBuilder().status(202).build()
}.getOrElse(ResponseBuilder.newBuilder().status(412).build())
As you can see. I receive a String, an evidence of a ResourceManager that implements the create method and a Manifest. When trying to serialize i make sure that the T type is of AnyRef but that is not the issue.
The problem is that m.runtimeClass returns Class[_] instead of Class[T].
My question is, if manifest does do what i want, how can i do this without explicitly passing the class name or whatever?
Thank you!
Basically I want null arrays to be deserialized as empty collection by Jackson with scala module. As I understand this is not implemented right now so I'm looking for a workaround. I think it could work if I have auxiliary constructor with Option[Seq[Any]] parameter. Like this:
case class Test (id: Int, seq: Seq[Any]){
#JsonCreator
def this(id: Int, seq: Option[Seq[Any]]) = this(id, seq.getOrElse(Seq()))
}
But it doesn't work since Jackson gives me this exception:
Caused by: java.lang.IllegalArgumentException: Conflicting
property-based creators: already had explicitly marked [constructor
for com.test.Main$Test, annotations: [null]], encountered [constructor
for com.test.Main$Test, annotations: {interface
com.fasterxml.jackson.annotation.JsonCreator=#com.fasterxml.jackson.annotation.JsonCreator(mode=DEFAULT)}]
It's interesting that if I remove id field it starts working:
case class Test (seq: Seq[Any]){
#JsonCreator
def this(seq: Option[Seq[Any]]) = this(seq.getOrElse(Seq()))
}
Could somebody explain me what is going on here?
Can I have overloaded constructor as json creator with case classes?
Maybe you see another workaround to my initial problem(deserializing null as empty collection)?
p.s. about my initial problem. I don't want to have Option[Seq[Any]] and I don't want to have getter because my constructor param will have ugly name like _seq and in scala parameter names is also a public API.
In order to avoid Java exceptions I'm using Scala's exception handling class.
However, when compiling the following snippet:
import scala.util.control.Exception._
val cls = classManifest[T].erasure
// Invoke special constructor if it's available. Otherwise use default constructor.
allCatch opt cls.getConstructor(classOf[Project]) match {
case Some(con) =>
con.newInstance(project) // use constructor with one Project param
case None =>
cls.newInstance // just use default constructor
};
I receive the following error:
error: type mismatch;
[scalac] found : java.lang.reflect.Constructor[_]
[scalac] required: java.lang.reflect.Constructor[_$1(in method init)] where
type _$1(in method init)
[scalac] allCatch opt cls.getConstructor(classOf[Project]) match {
[scalac] ^
[scalac] one error found
What's going on here and how can I fix it?
I have no explanation, but a much shorter example which I hope pinpoint where the problem occurs. I think it is not related at all to exceptions, nor to reflection. Whether this behavior is an arcane but correct consequence of the specification or a bug, I have no idea.
val untypedList : List[_] = List("a", "b")
val typedList : List[String] = List("a", "b")
def uselessByName[A](a: => A) = a
def uselessByValue[A](a: A) = a
uselessByName(untypedList) fails with the same error as your code. The other combinations do not. So combination of a method with a generic call-by-name argument, called with a parameter of a generic with an existential type.
uselessByName[List[_]](untypedList) works, so I guess if you call explicitly opt[Constructor[_]] it might work too.
The type inference scheme has gotten confused by the types available--specifically, by the type of cls. If we write generic code:
def clser[A](cls: Class[A]) = allCatch opt cls.getConstructor(classOf[Project])
then it works perfectly okay. But you're probably doing something else--I can't tell what because you didn't provide the code--and this results in a mismatch between the expected and actual types.
My currently solution is to cast the constructor explicitly.
cls.getConstructor(classOf[Project]) becomes cls.getConstructor(classOf[Project]).asInstanceOf[Constructor[Project]].
I'm still wondering about the actual error and if there are better ways to resolve it -- so I'm going to leave this open.