amnaredo / test

0 stars 0 forks source link

Unpickle failing from missing field in json #138

Open amnaredo opened 3 years ago

amnaredo commented 3 years ago

I'm running into a case where upickle is consistently throwing an exception while trying to unpickle a case class like

case class MyThing(uuid1: UUID, uuid2: UUID, name: String, boolOpt: Option[Boolean],
                   properties: Map[String, String] = Map.empty, uuid: UUID = UUID.randomUUID())

When the properties map has something in it, it's fine, but empty maps blow up ("Key missing: properties").

I have a pretty minimal example here: https://github.com/CodeMettle/upickle-boom

The interesting thing I've noticed is that if the test is only one project instead of two, it runs fine.

ID: 103 Original Author: codingismy11to7

amnaredo commented 3 years ago

Thanks for the repro! I'll take a look when I have the time...

Original Author: lihaoyi

amnaredo commented 3 years ago

The readme in the project says it, but it bears repeating - after enough changes to and incremental compiles of the model project, things work fine. So something's weird, and I don't know that it's something you're doing or something in the scala compiler, but I'll leave it up to you. In the time being I just make fake changes and recompile a few times until it starts working.

Original Author: codingismy11to7

amnaredo commented 3 years ago

I'm having the same issue... I whipped up another test using autowire because it resembled my usecase (I am only using upickle as the serializer with autowire):

import utest._
import autowire._
import upickle.default._

import scala.concurrent.ExecutionContext.Implicits.global

case class BooleanWrapper(bool: Boolean = false)
case class OptionBoolean(optBool: Option[Boolean] = Some(false))

trait BooleanApi {
  def show(bw: BooleanWrapper) = bw.toString
  def optionShow(optBw: OptionBoolean) = optBw.toString
}

object BooleanServer extends autowire.Server[String, Reader, Writer] {
  def write[Result: Writer](r: Result) = upickle.default.write(r)
  def read[Result: Reader](p: String) = upickle.default.read[Result](p)

  def routes = BooleanServer.route[BooleanApi](new BooleanApi {})
}

object BooleanClient extends autowire.Client[String, Reader, Writer] {
  def write[Result: Writer](r: Result) = upickle.default.write(r)
  def read[Result: Reader](p: String) = upickle.default.read[Result](p)

  override def doCall(req: Request) = {
    println(req)
    BooleanServer.routes.apply(req)
  }
}

object BooleanWrapperTest extends TestSuite {
  val tests = TestSuite {
    "invalid input when using default" - {
      BooleanClient[BooleanApi].show(BooleanWrapper()).call().foreach(println)
    }
    "invalid input even when explicitly provided value is same as default" - {
      BooleanClient[BooleanApi].show(BooleanWrapper(false)).call().foreach(println)
    }
    "valid input if provided value is not the same as default" - {
      BooleanClient[BooleanApi].show(BooleanWrapper(true)).call().foreach(println)
    }
    "invalid input when using wrapped default" - {
      BooleanClient[BooleanApi].optionShow(OptionBoolean()).call().foreach(println)
    }
    "invalid input even when explicitly provided wrapped value is same as default" - {
      BooleanClient[BooleanApi].optionShow(OptionBoolean(Some(false))).call().foreach(println)
    }
    "valid input if provided wrapped value is not the same as default" - {
      BooleanClient[BooleanApi].optionShow(OptionBoolean(Some(true))).call().foreach(println)
    }
  }

}

Original Author: matthewpflueger

amnaredo commented 3 years ago

Another quick note on this - I forked upickle and tried to reproduce the issue in the existing example tests and could not using Scala 2.10. Unfortunately, I could not get the tests to run utilizing Scala 2.11 due to my inability to get past an unresolved dependency on the derive project (building it and publishing locally did not seem to help).

Original Author: matthewpflueger

amnaredo commented 3 years ago

@matthewpflueger try bumping the version in project/repo.scala to a SNAPSHOT; otherwise SBT gets confused

Original Author: lihaoyi

amnaredo commented 3 years ago

Thanks, that worked. Unfortunately, I could not reproduce in the existing example tests. I put the test above in a working project which fails here: https://github.com/matthewpflueger/upickle-test

Original Author: matthewpflueger

amnaredo commented 3 years ago

Seems fixed by https://github.com/Voltir/upickle/commit/832756d3d8e1083ec00af6806f120b76f43f26ef. Thanks @Voltir!

Original Author: lihaoyi

amnaredo commented 3 years ago

203 seems the same issue. Sometimes it goes out, very frustrating.

Now I use 0.4.4, scala 2.11.8.

It seems when JSON serialized against sealed trait cannot be deserialized directly to subclass. Like:

sealed trait A{
  def toJSON:String = write(this)
}
case class B(maybe:Seq[String] = Seq()) extends A
object B {def fromJSON(in:String) = read[B](in)}
val json = B().toJSON
B.fromJSON(json) //maybe broken..  but for many times, it works.

I'll continue to watch. Original Author: cuzfrog