eed3si9n / sjson-new Goto Github PK
View Code? Open in Web Editor NEWa typeclass based JSON codec that's backend independent
License: Apache License 2.0
a typeclass based JSON codec that's backend independent
License: Apache License 2.0
These should be provided out the box.
I've imported LList.:*:
enough times already..
I think it would be an improvement if it was imported when importing sjsonnew._
, either by moving (or duplicating :-/) the type alias in the root package object, or by renaming LCons
to :*:
.
AdditionalFormats is mixed into BasicJsonProtocol (and from there into other implicit cakes).
This means that importing sjsonew.BasicJsonProtocol._
will make project
ambiguous between sbt's (macro) method) and this method.
I found this in fixing scripted tests when switching from sbinary to sjsonnew.
Feel free to close if you consider this a non-issue.
As per conversation with Joda author, OffsetDateTime is the ISO-8601 compatible representation of datetime.
It would be cool if tuple syntax were available on LList, such as instead of xs.tail.head
you could call x._2
. Note, like calling .tail.head
is a compile error on an LList of size 1, so would ._2
.
Make an object with a Vector field, serialize it to JSON.
The field is omitted. For example, in the following example, "diagnostics": []
is missing.
JsonRpcNotificationMessage(2.0, textDocument/publishDiagnostics, {"uri":"file:/xxx/Hello.scala"})
The receiver of the message is not happy.
Empty fields are not omitted.
This was an intentional design added in #6.
I think Option[A]
can continue to elide.
Here's a recent build of master: https://travis-ci.org/eed3si9n/sjson-new/builds/255776069
If you look carefully it goes from running the tests to checking binary compatibility with MiMa.
What's missing is running the benchmarks, as defined in .travis.yml
:
- sbt "so test" "so benchmark/jmh:run -i 10 -wi 3 -f1 -t1" "so mimaReportBinaryIssues"
If you run it locally it's more obvious:
> so benchmark/jmh:run -i 10 -wi 3 -f1 -t1
>
I think this is an interaction between the sbt/sbt#3353 regression and sbt-doge.
Although I personally think AST should be able to roundtrip from source, we can't assume insertion order to be preserved by various AST implementations.
As such LList encoding should probably use JArray.
It's way too simple to create or compose JsonFormat instances that end up throwing runtime errors.
Here's a sample when running sbt/sbt's "actions/all" scripted test:
[info] sjsonnew.SerializationException: Unexpected builder state: End
[info] at sjsonnew.package$.serializationError(package.scala:19)
[info] at sjsonnew.Builder.stateError(Builder.scala:184)
[info] at sjsonnew.Builder.beginArray(Builder.scala:66)
[info] at sbt.internal.util.HListFormat$$anon$2.write(HListFormat.scala:25)
[info] at sbt.internal.util.HListFormat$$anon$2.write(HListFormat.scala:23)
[info] at sbt.internal.util.HListFormat$$anon$2.write(HListFormat.scala:27)
[info] at sbt.internal.util.HListFormat$$anon$2.write(HListFormat.scala:23)
[info] at sjsonnew.SupportConverter$class.toJsonUnsafe(SupportConverter.scala:23)
[info] at sjsonnew.support.scalajson.unsafe.Converter$.toJsonUnsafe(Converter.scala:7)
[info] at sjsonnew.SupportConverter$$anonfun$toJson$1.apply(SupportConverter.scala:14)
[info] at scala.util.Try$.apply(Try.scala:192)
[info] at sjsonnew.SupportConverter$class.toJson(SupportConverter.scala:14)
[info] at sjsonnew.support.scalajson.unsafe.Converter$.toJson(Converter.scala:7)
[info] at sbt.internal.util.PlainOutput.write(Output.scala:15)
[info] at sbt.internal.util.FileBasedStore$$anonfun$write$1.apply(CacheStore.scala:39)
[info] at sbt.internal.util.FileBasedStore$$anonfun$write$1.apply(CacheStore.scala:39)
[info] at sbt.io.Using.apply(Using.scala:23)
[info] at sbt.internal.util.FileBasedStore.write(CacheStore.scala:39)
[info] at sbt.internal.util.Tracked$CacheHelp.save(Tracked.scala:58)
[info] at sbt.internal.util.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:52)
[info] at sbt.Classpaths$.cachedUpdate(Defaults.scala:1669)
[info] at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1519)
[info] at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1471)
I've hit this general problem in different manifestation over the last few weeks switching sbt's modules to sjson-new.
I've never run into these kinds of runtime errors when defining custom JSON typeclass instances using play-json.
The pattern guard
if implicitly[Manifest[A1]].runtimeClass == x.getClass
will never be true when A1
is PatternsBasedRepository
and x
is FileRepository
(a subclass of PatternsBasedRepository
).
Copied from the example for custom types in the README:
Welcome to Scala 2.12.3 (OpenJDK 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala> import sjsonnew._, LList.:*:
import sjsonnew._
import LList.$colon$times$colon
scala> import BasicJsonProtocol._
import BasicJsonProtocol._
scala> case class Person(name: String, value: Int)
defined class Person
scala> implicit val personIso = LList.iso(
| { p: Person => ("name", p.name) :*: ("value", p.value) :*: LNil },
| { case (_, name) :*: (_, value) :*: LNil => Person(name, value) })
<console>:22: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ? => ?
{ case (_, name) :*: (_, value) :*: LNil => Person(name, value) })
^
I'm also wary of whether this is even useful at all - doesn't the builder in this case require the order of the JSON properties to be the order that appears in the LList
? If that's so, it's not a compliant JSON converter, since compliant JSON converters should allow properties to appear in any order.
LList
proports itself as a "Heterogeneous list with labels", but if you look at the definition of LCons
:
final case class LCons[A1: JsonFormat: ClassManifest, A2 <: LList: JsonFormat](
name: String, head: A1, tail: A2
) extends LList {
// ..
}
.. it's defined in terms of types for which there exist JsonFormat
instances (and it captures them).
LList should either change its description, and possibly even its name, or it shouldn't capture JsonFormat
instances.
Try running sbt 1 on JDK 9.
[error] (*:update) java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter
#11 introduces dependency to JAXB, which is not part of the classpath on JDK 9. Figure out an alternative or add dependency to it.
Adding this test-case to sjsonnew.support.spray.CollectionFormatsSpec
, in "The mapFormat" should
:
"round trip a Map[Person, Int]" in assertRoundTrip(Map(person -> 1))
def assertRoundTrip[A: JsonWriter: JsonReader](x: A) = {
val jValue: JsValue = Converter.toJsonUnsafe(x)
val y: A = Converter.fromJsonUnsafe[A](jValue)
x mustEqual y
}
blows up with this:
[error] ! round trip a Map[Person, Int]
[error] sjsonnew.SerializationException: Unexpected builder state: InObject (package.scala:19)
[error] sjsonnew.package$.serializationError(package.scala:19)
[error] sjsonnew.Builder.stateError(Builder.scala:184)
[error] sjsonnew.Builder.beginObject(Builder.scala:111)
[error] sjsonnew.support.spray.CollectionFormatsSpec$PersonFormat$.write(CollectionFormatsSpec.scala:30)
[error] sjsonnew.support.spray.CollectionFormatsSpec$PersonFormat$.write(CollectionFormatsSpec.scala:28)
[error] sjsonnew.CollectionFormats$$anon$3$$anonfun$write$3.apply(CollectionFormats.scala:96)
[error] sjsonnew.CollectionFormats$$anon$3$$anonfun$write$3.apply(CollectionFormats.scala:94)
[error] sjsonnew.CollectionFormats$$anon$3.write(CollectionFormats.scala:94)
[error] sjsonnew.CollectionFormats$$anon$3.write(CollectionFormats.scala:88)
[error] sjsonnew.SupportConverter$class.toJsonUnsafe(SupportConverter.scala:23)
[error] sjsonnew.support.spray.Converter$.toJsonUnsafe(Converter.scala:6)
[error] sjsonnew.support.spray.CollectionFormatsSpec.assertRoundTrip(CollectionFormatsSpec.scala:119)
[error] sjsonnew.support.spray.CollectionFormatsSpec$$anonfun$3$$anonfun$apply$22.apply(CollectionFormatsSpec.scala:90)
[error] sjsonnew.support.spray.CollectionFormatsSpec$$anonfun$3$$anonfun$apply$22.apply(CollectionFormatsSpec.scala:90)
because Scala 3 generate _1
, _2
methods for case classes. LCons is case class
sjson-new/core/src/main/scala/sjsonnew/LList.scala
Lines 122 to 146 in a89ac90
Welcome to Scala 3.1.1-RC1 (1.8.0_312, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala> case class A(x1: Int, x2: String)
val a // defined case class A
scala> val a = A(2, "b")
val a: A = A(2,b)
scala> a._1
val res0: Int = 2
scala> a._2
val res1: String = b
scala> a._3
-- [E008] Not Found Error: -----------------------------------------------------
1 |a._3
|^^^^
|value _3 is not a member of A
1 error found
scala> implicit class AOps(self: A) { def _1 = "AOps._1" }
// defined class AOps
def AOps(self: A): AOps
scala> a._1
val res2: Int = 2
LListOps
?-final case class LCons[A1: JsonFormat: ClassTag, A2 <: LList: JsonFormat](name: String, head: A1, tail: A2) extends LList {
+final class LCons[A1: JsonFormat: ClassTag, A2 <: LList: JsonFormat](val name: String, val head: A1, val tail: A2) extends LList with Product with Serializable with Equals {
+ override def canEqual(that: Any): Boolean = that.isInstanceOf[LCons[_, _]]
+ override def productArity: Int = 3
+ override def productElement(n: Int): Any = n match {
+ case 0 => name
+ case 1 => head
+ case 2 => tail
+ case _ => throw new IndexOutOfBoundsException(Integer.toString(n))
+ }
+ def copy[B1: JsonFormat: ClassTag, B2 <: LList: JsonFormat](name: String = name, head: B1 = head, tail: B2 = tail): LCons[B1, B2] =
+ new LCons[B1, B2](name, head, tail)
+
+ override def hashCode(): Int = scala.runtime.ScalaRunTime._hashCode(this)
+
+ override def equals(x$1: Any): Boolean = x$1 match {
+ case that: LCons[_, _] =>
+ (this.name == that.name) && (this.head == that.head) && (this.tail == that.tail)
+ case _ =>
+ false
+ }
+
def :*:[B1: JsonFormat: ClassTag](labelled: (String, B1)): B1 :*: A1 :*: A2 = LCons(labelled._1, labelled._2, this)
override def toString: String = s"($name, $head) :*: $tail"
+ override def productPrefix: String = "LCons"
override def find[B1: ClassTag](n: String): Option[B1] =
if (name == n && implicitly[ClassTag[A1]] == implicitly[ClassTag[B1]]) Option(head match { case x: B1 @unchecked => x })
else tail.find[B1](n)
override def fieldNames: List[String] = name :: tail.fieldNames
}
+object LCons extends Serializable {
+ override def toString: String = "LCons"
+ def apply[A1: JsonFormat: ClassTag, A2 <: LList: JsonFormat](name: String, head: A1, tail: A2): LCons[A1, A2] =
+ new LCons[A1, A2](name = name, head = head, tail = tail)
+ def unapply[A1, A2 <: LList](x$0: LCons[A1, A2]): Option[(String, A1, A2)] =
+ if (x$0 == null) {
+ None
+ } else {
+ Some((x$0.name, x$0.head, x$0.tail))
+ }
+}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.