Hi All. I see that for release 0.5.1 there is a following note:
ujson.write now takes an optional `sortKeys` flag, if you want the JSON dictionaries to rendered in a standardized order
That flag sortKeys disappeared in the very next release and I do not see in there any notes wrt. removal of that flag. What is now a correct way of serializing map with a specific order for keys? And does such feature exists now?
upickle-core_3.0.0-M3/ - -
upickle-core_native0.3_2.11/ - -
upickle-core_native0.4.0-M2_2.11/ - -
upickle-core_native0.4_2.12/ - -
upickle-core_native0.4_2.13/ - -
upickle-core_sjs0.6_2.11/ - -
upickle-core_sjs0.6_2.12/ - -
upickle-core_sjs0.6_2.13/ - -
upickle-core_sjs0.6_2.13.0-M5/ - -
upickle-core_sjs1.0-RC2_2.12/ - -
upickle-core_sjs1.0-RC2_2.13/ - -
upickle-core_sjs1_2.12/ - -
upickle-core_sjs1_2.13/ - -
? Here's a list of actions you need to do (in this order)
* [ ] you'll need to publish com.lihaoyi:geny for 3.0.0-M3 (Scala.js)
* [ ] you'll need to publish com.lihaoyi:upickle-core for 3.0.0-M3 (Scala.js)
* [ ] you'll need to publish com.lihaoyi:upack for 3.0.0-M3 (Scala.js)
* [ ] you'll need to publish com.lihaoyi:upickle-implicits for 3.0.0-M3 (Scala.js)
* [ ] you'll need to publish com.lihaoyi:ujson for 3.0.0-M3 (Scala.js)
* [ ] you'll need to publish com.lihaoyi:upickle for 3.0.0-M3 (Scala.js)
Hey! I'm getting an error trying to read a ujson.Value into a case class. I'm getting the following error:
Caused by: java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:627)
at scala.None$.get(Option.scala:626)
at upickle.AttributeTagged$$anon$4.visitEnd(Api.scala:240)
at upickle.core.TraceVisitor$$anon$1.visitEnd(TraceVisitor.scala:122)
at ujson.AstTransformer.transformObject(AstTransformer.scala:21)
at ujson.AstTransformer.transformObject$(AstTransformer.scala:14)
at ujson.Value$.transformObject(Value.scala:131)
at ujson.Value$.transform(Value.scala:197)
at ujson.Value$.transform(Value.scala:131)
at ujson.AstTransformer.$anonfun$transformArray$1(AstTransformer.scala:11)
at ujson.AstTransformer.$anonfun$transformArray$1$adapted(AstTransformer.scala:11)
at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:553)
at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:551)
at scala.collection.AbstractIterable.foreach(Iterable.scala:920)
at ujson.AstTransformer.transformArray(AstTransformer.scala:11)
at ujson.AstTransformer.transformArray$(AstTransformer.scala:9)
at ujson.Value$.transformArray(Value.scala:131)
at ujson.Value$.transform(Value.scala:196)
at ujson.Value.transform(Value.scala:113)
at ujson.Value.transform$(Value.scala:113)
at ujson.Arr.transform(Value.scala:256)
at upickle.Api.$anonfun$read$1(Api.scala:37)
at upickle.core.TraceVisitor$.withTrace(TraceVisitor.scala:21)
at upickle.Api.read(Api.scala:37)
at upickle.Api.read$(Api.scala:36)
...
I've been searching everywhere to see if this sort of thing has been encountered before, and looking at the lines referenced in the stack trace hasn't shed any light. Does anyone know what might cause this failure?
True, sorry, should have provided some code and context! We're on Scala 2.13.3. @lihaoyi that's exactly it, extending a sealed trait.
import upickle.default._
sealed trait TestTrait
final case class Spot(name: String) extends TestTrait
implicit val spotReader: Reader[Spot] = macroR
val spot = """{"name": "TEST"}"""
read[Spot](spot)
We've been keeping our case class definitions separate from our reader definitions, as we prefer to keep the latter closer to our API-wrapping logic. Thus, we're not defining them in the companion object. Would that fix it, and is there any other way to do it separately from the definition of the case class? At this point we're preparing to manually write mappings from Js.Value to our case classes. We love the ujson AST, but we'll forego macroR if it denies us some of our flexibility.
import upickle.default.{ ReadWriter => RW, macroRW }
object BrandEntity {
final case class Brand(id: Option[BrandID], value: BrandValueObject)
final case class BrandID private (url: String)
final case class BrandValueObject private (name: Option[BrandName], country: Option[Country])
final case class BrandName private (name: String)
final case class Country private (country: String)
case class RawBrand(pageUrl: String, brandName: String, country: String)
// https://stackoverflow.com/questions/27941585/pattern-matching-to-check-if-string-is-null-or-empty
// vs
// https://youtu.be/BIt3jLLGY0s?t=729 (https://github.com/lutzh/pattern-matching-talk/blob/master/pattern-matching.txt)
// vs
// https://riptutorial.com/scala/example/3434/unapply---custom-extractors
object Brand {
implicit val rw: RW[Brand] = macroRW
def apply(rawBrand: RawBrand): Brand = {
Brand(BrandID(rawBrand.pageUrl), BrandValueObject(rawBrand.brandName, rawBrand.country))
}
}
object BrandID {
implicit val rw: RW[BrandID] = macroRW
// hide default ctor
private[this] def apply() = None
private[this] def unapply(url: String): Option[String] = if (url == null || url.trim.isEmpty) None else Some(url)
def apply(url: String): Option[BrandID] = {
url match {
case BrandID(url) => Some(new BrandID(url))
case _ => None
}
}
}
object BrandValueObject {
implicit val rw: RW[BrandValueObject] = macroRW
// hide default ctor
private[this] def apply() = new BrandValueObject(None, None)
private[BrandEntity] def isEmpty(value: String) = (value == null || value.trim.isEmpty)
def apply(name: String, country: String) = {
(name, country) match {
case (name, country) if (isEmpty(name) && isEmpty(country)) => new BrandValueObject(None, None)
case (name, country) if (isEmpty(name)) => new BrandValueObject(None, Some(Country(country)))
case (name, country) if (isEmpty(country)) => new BrandValueObject(Some(BrandName(name)), None)
case _ => new BrandValueObject(Some(BrandName(name)), Some(Country(country)))
}
}
}
object BrandName {
implicit val rw: RW[BrandName] = macroRW
// hide default ctor
private[BrandEntity] def apply() = new BrandName("")
private[BrandEntity] def apply(name: String) = new BrandName("")
}
object Country {
implicit val rw: RW[Country] = macroRW
// hide default ctor
private[BrandEntity] def apply() = new Country("")
private[BrandEntity] def apply(name: String) = new Country("")
}
}
[error] ...../01-entities/src/main/scala/de/mobe/scraper/entities/Brand.scala:31:36: type mismatch;
[error] found : Option[de.mobe.scraper.entities.BrandEntity.BrandID]
[error] required: de.mobe.scraper.entities.BrandEntity.BrandID
[error] implicit val rw: RW[BrandID] = macroRW
@kiviuk I guess upickle.default.macroRW
macro is trying to use BrandId.apply
method to instantiate BrandID
but it returns different type (Option[BrandID]
instead of BrandID
). You can provide proper apply method that blows when data is invalid :(.
implicit val rw: ReadWriter[charData] =
readwriter[ujson.Value].bimap[charData](
charData =>
ujson.Arr(
charData.num,
write(charData.address),
...ReadWrite
value.
writeJS
I guess. It serialize your Address
to ujson's AST. I've propose also Reader
implementation :)
ScalaFiddle.scala:31: error: The referenced trait [[BrandID]] does not have any sub-classes. This may happen due to a limitation of scalac (SI-7046). To work around this, try manually specifying the sealed trait picklers as described in http://www.lihaoyi.com/upickle/#ManualSealedTraitPicklers
implicit val rw: RW[BrandID] = macroRW
^
ScalaFiddle.scala:40: error: class BrandID is abstract; cannot be instantiated
case BrandID(url) => Some(new BrandID(url))
^