I am facing an issue with Companion Objects picking up its type instead of the case class
I am using spray json serdes. They need an implicit JsonFormat. This format is obtained by calling a function that depends on the number of parameters of the case class: jsonFormat2(Class2) if case class has two fields, like
case class Class2(a: String, b: Integer)
or jsonFormat3(Class3) for
case class Class3(a: String, b: Integer, c: Long)
Given that having to know the number of params your case class have throughout the code is not nice, I wanted to make a case class companion object so you can encapsulate this info and get the JsonFormat from the class itself, like:
object Class2 extends DefaultJsonProtocol
{
def getJsonFormat() = {
jsonFormat2(Class2)
}
}
But if I do so, I'll get the following compilation issue:
type mismatch;
[error] found : mypackage.Class2.type
[error] required: (?, ?) => ?
[error] jsonFormat2(Class2)
If we look at the code in jsonFormat2, the signature is:
def jsonFormat2[P1 :JF, P2 :JF, T <: Product :ClassManifest
(construct: (P1, P2) => T): RootJsonFormat[T] = { // ...
If I change the companion object name (e.g. to MyClass2) it will just work. So, it seems types are conflicting.
It seems like when dealing with typing, companion objects would not be able to be named like the class they go with.
Could somebody please explain why this is happening, if there is a limitation, or otherwise how to work it around, so companion object can be used with the same name?
When a companion object for Class2
is defined implicitly, it extends (String, Integer) => Class2
; your version doesn't. If you change to
object Class2 extends DefaultJsonProtocol with (String, Integer) => Class2 { ... }
it will work, but to avoid duplicating parameter types I'd go with Andrey Tyukin's suggestion (even if the explanation is incorrect).
Your definition of object Class2
does not extend (String, Integer) => Class2
. You might want to pass the apply
-method explicitly:
case class Class2(a: String, b: Integer)
object Class2 extends DefaultJsonProtocol
{
def getJsonFormat() = {
jsonFormat2(Class2.apply)
}
}
Inspired by @AlexeyRomanov's helpful comment, I decided to add a slightly more detailed explanation why it works when you don't define a companion object, and why it stops working when you define it as object Class2 { ... }
.
If you compile
class Foo(n: Int, s: String)
then the decompiled code of the automatically generated companion object looks as follows:
public final class Foo$
extends AbstractFunction2<Object, String, Foo>
implements Serializable {
/* some lines omitted */
public Foo apply(int n, String s) {
return new Foo(n, s);
}
/* some lines omitted */
}
that is, it extends AbstractFunction2
, and therefore conforms to (?, ?) => ?
.
When you define object Foo
on your own, the generated object does not extends
(Int, String) => Foo
. This is why it stops working when you define a companion
object on your own without extending Function
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With