Why is structural equality comparison affected, after deserialisation to case class instance, by the location of case class definition being inside or outside another class. For example, the assertion in the following snippet
package example
import org.json4s.DefaultFormats
import org.json4s.native.JsonMethods.parse
class Foo {
case class Person(name: String)
def bar = {
implicit val formats = DefaultFormats
val expected = Person(name = "picard")
val actual = parse("""{"name": "picard"}""").extract[Person]
assert(expected == actual, s"$expected == $actual")
}
}
object Main extends App {
(new Foo).bar
}
fails with
`java.lang.AssertionError: assertion failed: Person(picard) == Person(picard)`
whilst it passes if we move Person definition outside class Foo like so
case class Person(name: String)
class Foo {
def bar = {
...
assert(expected == actual, s"$expected == $actual")
}
}
Note, in both cases, deserialisation seems to be successful, for example,
assert(expected.name == actual.name)
is satisfied irrespective of case class Person definition location.
Perhaps it is somehow affected by the implicit Manifest passed in to extract?
This is a bug.
https://github.com/json4s/json4s/issues/564
"Deserialized inner case classes cannot be compared with case classes initialized in code"
Looks like inner classes can't be meaningfully checked for equality since every instance holds a reference to the outer object. And these references are a part of equality check:
class Outer {
case class Inner(s: String)
}
val outer = new Outer()
val a = outer.Inner("x")
val b = outer.Inner("x")
println(a==b) //true
val c = new Outer().Inner("x")
println(a==c) //false
Related
I need to access a companion class with a specified trait -- from a trait intended for case classes. I am almost certain that the Scala reflection library can accomplish this but I haven't quite been able to piece it together.
I created test code below that requires one section of ??? be filled in with some reflection magic. The code compiles and runs as is -- with a notification due to the missing functionality.
Some related answers that I have seen on StackOverflow were from 2.10. Scala 2.12 compatible please.
import scala.reflect.{ClassTag, classTag}
//for companion object
//accesses Fields of the associated case class to ensure the correctness
//note: abstract class -- not a trait due to issues using ClassTag on a trait
abstract class SupportsField1Companion[T: ClassTag] {
//gets the names of all Fields on the associated case class
val fieldNamesOfInstancedClass: Array[String] =
classTag[T].runtimeClass.getDeclaredFields.map(_.getName)
//prints the name and fields of the associated case class -- plus extra on success
def printFieldNames(extra: String = ""): Unit = {
val name = classTag[T].runtimeClass.getCanonicalName
val fields = fieldNamesOfInstancedClass.reduceLeft(_ + ", " + _)
println(s"Fields of $name: $fields" + extra)
}
}
//for case classes
//IMPORTANT -- please do not parameterize this if possible
trait SupportsField1 {
//some data for printing
val field1: String = this.getClass.getCanonicalName + ": field1"
//should get a reference to the associated companion object as instance of SupportsFieldsCompanion
def getSupportsFieldsCompanion: SupportsField1Companion[this.type] = //this.type may be wrong
??? //TODO reflection magic required -- need functionality to retrieve companion object cast as type
//calls a function on the associated Companion class
def callPrintFuncOnCompanion(): Unit =
getSupportsFieldsCompanion.printFieldNames(s" -- from ${this.getClass.getCanonicalName}")
}
//two case classes with the SupportsFieldsCompanion trait to ensure data is accessed correctly
object ExampleA extends SupportsField1Companion[ExampleA] {}
case class ExampleA() extends SupportsField1 {
val fieldA: String = "ExampleA: fieldA"
}
object ExampleB extends SupportsField1Companion[ExampleB] {}
case class ExampleB() extends SupportsField1 {
val fieldB: String = "ExampleB: fieldB"
}
object Run extends App {
//create instanced classes and print some test data
val exampleA = ExampleA()
println(exampleA.field1) //prints "ExampleA: field1" due to trait SupportsFields
println(exampleA.fieldA) //prints "ExampleA: fieldA" due to being of class ExampleA
val exampleB = ExampleB()
println(exampleB.field1) //prints "ExampleB: field1" due to trait SupportsFields
println(exampleB.fieldB) //prints "ExampleB: fieldB" due to being of class ExampleB
//via the SupportsFieldsCompanion trait on the companion objects,
//call a function on each companion object to show that each companion is associated with the correct case class
ExampleA.printFieldNames() //prints "Fields of ExampleA: fieldA, field1"
ExampleB.printFieldNames() //prints "Fields of ExampleB: fieldB, field1"
//test access of printFieldNames on companion object from instanced class
try {
exampleA.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleA: fieldA, field1 -- from ExampleA"
exampleB.callPrintFuncOnCompanion() //on success, prints "Fields of ExampleB: fieldB, field1 -- from ExampleB"
} catch {
case _: NotImplementedError => println("!!! Calling function on companion(s) failed.")
}
}
There are lots of ways you can do this, but the following is probably one of the simplest that doesn't involve making assumptions about how Scala's companion object class name mangling works:
def getSupportsFieldsCompanion: SupportsField1Companion[this.type] =
scala.reflect.runtime.ReflectionUtils.staticSingletonInstance(
this.getClass.getClassLoader,
this.getClass.getCanonicalName
).asInstanceOf[SupportsField1Companion[this.type]]
This works as desired, but I'd probably type it as SupportsField1Companion[_], and ideally I'd probably avoid having public methods on SupportsField1 that refer to SupportsField1Companion—actually ideally I'd probably avoid this approach altogether, but if you're committed I think the ReflectionUtil solution above is probably reasonable.
Is there a way to get the parent class from an instance of an inner class using macros rather than run-time reflection?
I have a set of classes like this:
trait IdProvider {
type IdObject = Id.type
case class Id(underlying: Int)
}
case class SomeEntity(id: SomeEntity.Id)
object SomeEntity extends IdProvider
And some code that works with arbitrary IdProvider#Ids:
val lookup = Map[IdProvider#IdObject, Set[Operation]]
def can(operation: Operation, id: IdProvider#Id): Boolean = {
val idObject = findIdTypeFromInstance(id) // This is what I don't have
lookup.get(idObject).exists(s => s(operation))
}
Taking a leaf out of this gist by Paul P. I now have this macro:
def findIdTypeFromInstance[T <: AnyRef : c.WeakTypeTag](
c: blackbox.Context)(thing: c.Expr[T]): c.Expr[T] = {
import c.universe._
val companion = thing.actualType.typeSymbol.companion match {
case NoSymbol =>
c.abort(c.enclosingPosition, s"Instance of ${thing.actualType} has no companion object")
case sym => sym
}
def make[U: c.WeakTypeTag] = c.Expr[U](internal.gen.mkAttributedRef(companion))
make(c.WeakTypeTag(companion.typeSignature))
}
This works for simpler cases (top level case classes, classes and objects, and even nested case classes). However, when dealing with the IdProvider setup above the macro tries to generate this tree:
Select(This(TypeName("IdProvider")), TermName("Id"))
This results in an extremely long stack trace in my test, which starts with:
scala.reflect.internal.Types$TypeError: value is not a member of my.spec.MacroSpec
I have not been able to find a path from the instance or the companion (IdProvider#Id) to the parent class (in this case SomeEntity). Is there a way to get to SomeEntity or do I have to use run-time reflection?
The Id companion is basically a lazy val. You need the enclosing instance to retrieve its value because it's not a statically defined stable path.
With -Yshow-syms you can see it get added in mixin phase:
object SomeEntity
constructor SomeEntity
* method Id$lzycompute (private)
method apply (case <synthetic>)
value id
method readResolve (private <synthetic>)
method unapply (case <synthetic>)
value x$0 (<synthetic>)
* object Id (<synthetic> <stable>)
value <local SomeEntity>
* variable Id$module (private <local> <synthetic>)
The $outer field of an Id is added in explicitouter.
Is it easier just to expose the companion reference explicitly?
case class Id(underlying: Int) {
def c = Id
}
This is just a quick look; maybe there's a clever way to do it.
I'm trying to write a convenience function that replaces the left tree of an immutable binary tree, and I'm getting "Error occurred in an application involving default arguments" in the following replaceL method:
abstract class AbNode {
val key = null
val value = null
val leftTree:AbNode = NullNode
val rightTree:AbNode = NullNode
}
case class Node[K <:Ordered[K],V](k:K, v:V, lT:AbNode, rT:AbNode) extends AbNode {
val key:K = k
val value:V = v
val leftTree:AbNode = lT
val rightTree:AbNode = rT
}
object Node {
def replaceL[K <: Ordered[K],V](newTree:AbNode, node:Node[K,V]): Node[K,V] =
node.copy(leftTree = newTree) //<< Error occurs here
}
case object NullNode extends AbNode {
val key = null
val value = null
val leftTree = NullNode
val rightTree = NullNode
}
The copy method (and default parameters in general) use the name used in the constructor, not the field name that you assign it to (I don't know why this didn't click sooner).
In the case of a case class, the assigned fields are useless; as far as I can tell, they're simply holding a copy of a reference to the constructor value (not my original intent). I think my confusion stemmed from the fact that in C-style languages, the variables given to a constructor are later assigned to a field. In other words, the way I have my classes set-up is non-sensical, they shouldn't have any fields.
My Node class should be simply:
case class Node[K <:Ordered[K],V](k:K, v:V, leftTree:AbNode, rightTree:AbNode) extends AbNode
Which allows copy to see the value I'm referring to.
I need to convert a string value into an actual type, so i decided to try a macro-way to do this. I have a bunch of data types:
sealed abstract class Tag(val name: String)
case object Case1 extends Tag("case1")
case object Case2 extends Tag("case2")
case object Case3 extends Tag("case3")
etc...
I want to write a simple resolver:
val tag: Tag = TagResolver.fromString("case2")
This line should return Case2 respectively. I manager to do the following:
def typeFromString(c: Context)(name: c.Expr[String]): c.Expr[Tag] = {
import c.universe._
val tag = typeTag[Tag]
val accSymb = tag.tpe.typeSymbol.asClass
val subclasses = accSymb.knownDirectSubclasses // all my cases
subclasses.map { sub =>
val name = sub.typeSignature.member(newTermName("name")).asMethod // name field
???
}
}
But how can i match name: c.Expr[String] against value of name field and if matched return the appropriate tag?
I don't think there's reliable way of doing this, because knownDirectSubclasses can refer to classes that haven't been compiled yet, so we can't evaluate them.
If you can put these values as annotations on the classes, then these annotations can be read even when classes are being compiled in the current compilation run (via the Symbol.annotations API). Please note, however, that knownDirectSubclasses has known issues: https://issues.scala-lang.org/browse/SI-7046.
I'm trying to use Scala reflection to define traits case classes and their companions could implement to become "exportable" (e.g. to Map[String,Any]) and "importable" from the same. It's working nicely for top level case classes, but I can't make it work for inner classes. I would know how to instantiate an inner class reflectively if I already had a handle on the enclosing instance, which i could reflect to an InstanceMirror, but for now I am writing a trait that will be implemented later, by top-level or inner classes.
I should be able to make this work, as long as the companion and the constructed instances will share the same enclosing instance. But I've not been able to figure out how to determine the companion's enclosing instance reflectively.
Here's a way simplified example of what I am trying to do, and the problem that occurs:
import scala.reflect.runtime.universe._;
trait CompanionOfReflectiveConstructable[T] {
def tType : Type;
lazy val mirror : Mirror = runtimeMirror( this.getClass.getClassLoader );
lazy val ctorDecl : Symbol = tType.declaration(nme.CONSTRUCTOR);
lazy val ctor : MethodSymbol = ctorDecl.asMethod;
lazy val tClass : ClassSymbol = tType.typeSymbol.asClass;
lazy val tClassMirror : ClassMirror = mirror.reflectClass( tClass );
lazy val ctorF : MethodMirror = tClassMirror.reflectConstructor( ctor );
// in real-life, i'd derive arguments from ctor.paramss
// but to highlight our issue, we'll assume a no arg constructor
def createInstance : T = ctorF().asInstanceOf[T];
}
trait ReflectiveConstructable;
object Test1 extends CompanionOfReflectiveConstructable[Test1] {
def tType = typeOf[Test1];
}
class Test1 extends ReflectiveConstructable;
class Outer {
object Test2 extends CompanionOfReflectiveConstructable[Test2] {
def tType = typeOf[Test2];
}
class Test2 extends ReflectiveConstructable;
}
Here's what happens.
scala> Test1.createInstance
res0: Test1 = Test1#2b52833d
scala> (new Outer).Test2.createInstance
scala.ScalaReflectionException: class Test2 is an inner class, use reflectClass on an InstanceMirror to obtain its ClassMirror
at scala.reflect.runtime.JavaMirrors$JavaMirror.ErrorInnerClass(JavaMirrors.scala:126)
...
Test1 works great. The problem with Test2 is clear -- I need to to get my ClassMirror via an InstanceMirror rather than via my top level mirror. (See here, here, and here.) But, from within CompanionOfReflectiveConstructable, I don't know how to check whether I am inner or who my enclosing instance is, to conditionally perform the appropriate work. Does anyone know how to do this?
Many thanks!
The main problem that I see here is that you're using reflection inside of the companion object of an inner class. The class Test2 will have a field defined called $outer that contains the outer class, however, from the Test2 companion object, you cannot get the instance of Outer that you need to create Test2. The only work around that I can see, is to pass an optional instance to you're companion trait:
trait CompanionOfReflectiveConstructable[T] {
def tType: Type
def outer: Option[AnyRef] = None
val mirror = runtimeMirror(this.getClass.getClassLoader)
val tClassMirror = outer
.map(a => mirror.reflect(a).reflectClass(tType.typeSymbol.asClass))
.getOrElse(mirror.reflectClass(tType.typeSymbol.asClass))
val ctorF = tClassMirror.reflectConstructor(tType.declaration(nme.CONSTRUCTOR).asMethod)
// in real-life, i'd derive arguments from ctor.paramss
// but to highlight our issue, we'll assume a no arg constructor
def createInstance: T = ctorF().asInstanceOf[T]
}
trait ReflectiveConstructable
class Test1 extends ReflectiveConstructable
object Test1 extends CompanionOfReflectiveConstructable[Test1] {
def tType = typeOf[Test1]
}
class Outer {
object Test2 extends CompanionOfReflectiveConstructable[Test2] {
def tType = typeOf[Test2]
override def outer = Option(Outer.this)
}
class Test2 extends ReflectiveConstructable
}
It would be nice if there was a way to get the Outer instance from the Test2 companion object, but sadly it's not available at runtime.