amnaredo / test

0 stars 0 forks source link

Serialize to empty object {} in js/jvm project, while err "Key Missing:" in reading on the other side. #209

Open amnaredo opened 3 years ago

amnaredo commented 3 years ago

This is a serious bug:

case class definition:

private case
class ItemFormState(id: Long = -1,
                    sourceType: SourceType = SourceType.Original,
                    isSaving: Boolean = false,
                    values: Map[String, String] = {
                      //initial values
                      Map(
                        ID_DataFormat -> Constants.dataFormat.head,
                        ID_DataPeriod -> Constants.dataPeriod.head,
                        ID_ItemBassType -> Constants.itemBassTypeSet.head.toString
                      )
                    },
                    invalids: Map[String, String] = Map()
                   )

test:

val cs = ItemFormState()
          println(cs)
          println(write(cs))

result:

ItemFormState(-1,Original,false,Map(dataFormat -> Hit, dataPeriod -> Day, itemBassType -> Historical),Map())
{}  // well, this must be intentionally made to be empty.

While, on the server, read complains cannot find id ID: 203 Original Author: cuzfrog

amnaredo commented 3 years ago

This is probably caused by continuous compilation, in which there is a cache incongruity between macro-generated code and updated user code. sbt clean and recompilation solved above issue so far.

But there's another scenario that can't be solved by clean, described blow: Original Author: cuzfrog

amnaredo commented 3 years ago
import upickle.default._

sealed trait Message{
  def err:Seq[String]
}
object Message{
  def fromJSON(in:String):Message = read[Message](in)

  private implicit val readWriter: ReadWriter[Message] =
    macroRW[PhoneMessage] merge macroRW[PcMessage]
}

case class PhoneMessage(phone:String,err:Seq[String] = Seq()) 
  extends Message{
    def toJSON:String = write(this)
  }
case class PcMessage(pc:String,err:Seq[String] = Seq()) 
  extends Message{
    def toJSON:String = write(this)
  }

val msg = PcMessage("iMac").toJSON

println(Message.fromJSON(msg))

I tested above, which works fine on jvm. But "Key Missing" occurs when using remotely. Original Author: cuzfrog

amnaredo commented 3 years ago

@cuzfrog can you elaborate what you mean with "when using remotely"?

I just ran into the same problem I think. when I test the reading/writing in the sbt console it works fine. but when it runs on the jvm it fails with the "key missing" message, even though the default parameters are specified. Original Author: torstenrudolf

amnaredo commented 3 years ago

in my case it didn't work when having a companion object next to the case class. after I renamed the object to something else it worked. -.- I had the same behaviour previously with a problem with a sealed trait hierarchy. but in the light of #209 it is probably unfortunately time to switch to a different lib ;/ Original Author: torstenrudolf

amnaredo commented 3 years ago

@torstenrudolf

what you mean with "when using remotely"?

js to jvm.

I reckon this problem arises when one of the conditions meets:

  1. Inconsistency between macro-generated code and source code. When class signature changes, incremental compilation may fail to detect the change on one/both side(s) of jvm or js.
  2. In a class hierarchy, serialization done by sub-classes is to be deserialized by super-class(see my example above). This may be uPickle's deficiency.

Solutions:

  1. Clean to make a full compilation. See sbt's doc about incremental compilation, where you may find hints on how to minimize this problem.
  2. read or write class hierarchy in top class:
sealed trait Message{
  def err:Seq[String]

  def toJSON: String = write(this) //serialize this here.
}
object Message{
  def fromJSON(in:String):Message = read[Message](in)

  implicit val readWriter: ReadWriter[Message] =
    macroRW[PhoneMessage] merge macroRW[PcMessage] // when implicit val is public, it can be seen from trait.
}

I think i didn't see the problem anymore when applied these solutions/principles. Original Author: cuzfrog

amnaredo commented 3 years ago

my problem persisted after sbt clean

in my case it failed with a very simple case class with no hierarchy:

case class X(a: Option[String] = None, b: Option[String] = None)

object X {
  def something...
}

When reading in "{}" it would fail with key missing error (even after full compilation). but after I changed the object's name it worked. Original Author: torstenrudolf

amnaredo commented 3 years ago

Bug bankruptcy Original Author: lihaoyi