Skip to content

Commit

Permalink
Merge pull request #33 from tethys-json/dev-0.7.0
Browse files Browse the repository at this point in the history
Release 0.7.0
  • Loading branch information
eld0727 authored Sep 3, 2018
2 parents 3098c97 + af2be6d commit 118af70
Show file tree
Hide file tree
Showing 18 changed files with 536 additions and 36 deletions.
32 changes: 30 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ tethys is a JSON parsing/writing library for Scala
Add dependencies to your `build.sbt`

```scala
val tethysVersion = "0.6.3.2"
val tethysVersion = "0.7.0"
libraryDependecies ++= Seq(
"com.tethys-json" %% "tethys-core" % tethysVersion,
"com.tethys-json" %% "tethys-jackson" % tethysVchrersion,
Expand All @@ -22,10 +22,17 @@ or just

```scala
libraryDependecies ++= Seq(
"com.tethys-json" %% "tethys" % "0.6.3.1"
"com.tethys-json" %% "tethys" % "0.7.0"
)
```

Also tethys has following integrations:
#### Json4s
[see project page](https://github.com/json4s/json4s)
```scala
libraryDependencies += "com.tethys-json" %% "tethys-json4s" % tethysVersion
```

# core

core module contains all type classes for parsing/writing JSON.
Expand Down Expand Up @@ -224,4 +231,25 @@ case class Bar(seq: Seq[Int])

val foo = """{"bar":{"seq":[1,2,3]}}""".jsonAs[Foo].fold(throw _, identity)
val json = foo.asJson
```

# json4s AST support

In some cases, you may need to work with raw AST,
so tethys can offer you json4s AST support:
```scala
import tethys._
import tethys.jackson._
import tethys.derivation.semiauto._
import tethys.json4s._

import org.json4s.JsonAST._

case class Foo(bar: Int, baz: JValue)

val json = """{"bar": 1, "baz": ["some", {"arbitrary": "json"}]"""
val foo = json.jsonAs[Foo].fold(throw _, identity)

foo.bar // 1
foo.baz // JArray(List(JString("some), JObject("arbitrary" -> JString("json"))))
```
37 changes: 28 additions & 9 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
lazy val scalaTestVersion = "3.0.5"

lazy val commonSettings = Seq(
version := "0.6.3.2",
version := "0.7.0",
organization := "com.tethys-json",
scalaVersion := "2.11.12",
crossScalaVersions := Seq("2.11.12", "2.12.6"),
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.0.1" % "test"
),
crossScalaVersions := Seq("2.11.12", "2.12.6", "2.13.0-M2"),

licenses := Seq("Apache-2.0" -> url("https://www.apache.org/licenses/LICENSE-2.0")),
homepage := Some(url("https://github.com/tethys-json/tethys")),
Expand Down Expand Up @@ -37,20 +36,25 @@ lazy val commonSettings = Seq(
lazy val tethys = project.in(file("."))
.settings(commonSettings)
.dependsOn(core, `macro-derivation`, `jackson-backend`)
.aggregate(core, `macro-derivation`, `jackson-backend`)
.aggregate(core, `macro-derivation`, `jackson-backend`, json4s)

lazy val core = project.in(file("./modules/core"))
.settings(commonSettings)
.settings(
name := "tethys-core"
name := "tethys-core",
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % scalaTestVersion % Test
)
)

lazy val `macro-derivation` = project.in(file("./modules/macro-derivation"))
.settings(commonSettings)
.settings(
name := "tethys-derivation",
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided"
"org.scala-lang" % "scala-compiler" % scalaVersion.value % "provided",

"org.scalatest" %% "scalatest" % scalaTestVersion % Test
)
).dependsOn(core)

Expand All @@ -59,13 +63,28 @@ lazy val `jackson-backend` = project.in(file("./modules/jackson-backend"))
.settings(
name := "tethys-jackson",
libraryDependencies ++= Seq(
"com.fasterxml.jackson.core" % "jackson-core" % "2.9.1"
"com.fasterxml.jackson.core" % "jackson-core" % "2.9.1",

"org.scalatest" %% "scalatest" % scalaTestVersion % Test
)
).dependsOn(core)

lazy val json4s = project.in(file("./modules/json4s"))
.settings(commonSettings)
.settings(
name := "tethys-json4s",
libraryDependencies ++= Seq(
"org.json4s" %% "json4s-core" % "3.5.3",

"org.scalatest" %% "scalatest" % scalaTestVersion % Test
)
).dependsOn(core)

lazy val benchmarks = project.in(file("./modules/benchmarks"))
.settings(commonSettings)
.settings(
scalaVersion := "2.11.11",
crossScalaVersions := Seq("2.11.11"),
publishTo := None,
libraryDependencies ++= Seq(
"io.spray" %% "spray-json" % "1.3.3",
Expand Down
49 changes: 49 additions & 0 deletions modules/core/src/main/scala/tethys/JsonStreaming.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package tethys

import tethys.readers.{FieldName, ReaderError}
import tethys.readers.tokens.TokenIterator
import tethys.writers.tokens.TokenWriter

object JsonStreaming {

def streamValue(from: TokenIterator, to: TokenWriter)(implicit fieldName: FieldName): Unit = writeCurrentValue(from, to)

private def writeCurrentValue(it: TokenIterator, writer: TokenWriter)(implicit fieldName: FieldName): Unit = {
val token = it.currentToken()
if (token.isArrayStart) writeArray(it, writer)
else if (token.isObjectStart) writeObject(it, writer)
else if (token.isStringValue) writer.writeString(it.string())
else if (token.isNumberValue) writer.writeRawNumber(it.number())
else if (token.isBooleanValue) writer.writeBoolean(it.boolean())
else if (token.isNullValue) writer.writeNull()
else ReaderError.wrongJson(s"Expects value start but $token found")
it.next()
}

private def writeArray(it: TokenIterator, writer: TokenWriter)(implicit fieldName: FieldName): Unit = {
it.next()
writer.writeArrayStart()
var index: Int = 0
while (!it.currentToken().isArrayEnd) {
writeCurrentValue(it, writer)(fieldName.appendArrayIndex(index))
index = index + 1
}
writer.writeArrayEnd()
}

private def writeObject(it: TokenIterator, writer: TokenWriter)(implicit fieldName: FieldName): Unit = {
it.next()
writer.writeObjectStart()
while (!it.currentToken().isObjectEnd) {
val token = it.currentToken()
if(token.isFieldName) {
val name = it.fieldName()
writer.writeFieldName(name)
writeCurrentValue(it.next(), writer)(fieldName.appendFieldName(name))
} else {
ReaderError.wrongJson(s"Expects field name but $token found")
}
}
writer.writeObjectEnd()
}
}
26 changes: 26 additions & 0 deletions modules/core/src/main/scala/tethys/commons/RawJson.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tethys.commons

import java.io.StringWriter

import tethys.readers.FieldName
import tethys.readers.tokens.TokenIterator
import tethys.writers.tokens.{TokenWriter, TokenWriterProducer}
import tethys.{JsonReader, JsonStreaming, JsonWriter}

final case class RawJson(json: String)

object RawJson {
implicit val rawJsonWriter: JsonWriter[RawJson] = new JsonWriter[RawJson] {
override def write(value: RawJson, tokenWriter: TokenWriter): Unit = tokenWriter.writeRawJson(value.json)
}

implicit def rawJsonReader(implicit tokenWriterProducer: TokenWriterProducer): JsonReader[RawJson] = new JsonReader[RawJson] {
override def read(it: TokenIterator)(implicit fieldName: FieldName): RawJson = {
val stringWriter = new StringWriter()
val tokenWriter: TokenWriter = tokenWriterProducer.forWriter(stringWriter)
JsonStreaming.streamValue(it, tokenWriter)
tokenWriter.flush()
RawJson(stringWriter.toString)
}
}
}
2 changes: 1 addition & 1 deletion modules/core/src/main/scala/tethys/commons/Token.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package tethys.commons

trait Token {
sealed trait Token {
def isStringValue: Boolean = false

def isNumberValue: Boolean = false
Expand Down
10 changes: 9 additions & 1 deletion modules/core/src/main/scala/tethys/commons/TokenNode.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package tethys.commons

import tethys.JsonReader
import tethys.commons.Token._
import tethys.readers.tokens.TokenIteratorProducer
import tethys.readers.ReaderError
import tethys.readers.tokens.{QueueIterator, TokenIteratorProducer}

sealed trait TokenNode {
def token: Token
Expand Down Expand Up @@ -75,7 +77,9 @@ object TokenNode {
def value(v: Float): List[TokenNode] = FloatValueNode(v) :: Nil
def value(v: Double): List[TokenNode] = DoubleValueNode(v) :: Nil
def value(v: BigInt): List[TokenNode] = NumberValueNode(v) :: Nil
def value(v: java.math.BigInteger): List[TokenNode] = NumberValueNode(v) :: Nil
def value(v: BigDecimal): List[TokenNode] = NumberValueNode(v) :: Nil
def value(v: java.math.BigDecimal): List[TokenNode] = NumberValueNode(v) :: Nil

private def anyToTokens(any: Any): List[TokenNode] = any match {
case v: TokenNode => v :: Nil
Expand Down Expand Up @@ -128,4 +132,8 @@ object TokenNode {
builder.result()
}
}

implicit class TokenListOps(val tokens: Seq[TokenNode]) extends AnyVal {
def tokensAs[A: JsonReader]: A = QueueIterator(tokens).readJson[A].fold(throw _, identity)
}
}
8 changes: 8 additions & 0 deletions modules/core/src/main/scala/tethys/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ package object tethys {
stringWriter.toString
}

def asJsonWith(jsonWriter: JsonWriter[A])(implicit tokenWriterProducer: TokenWriterProducer): String = {
asJson(jsonWriter, tokenWriterProducer)
}

def writeJson(tokenWriter: TokenWriter)(implicit jsonWriter: JsonWriter[A]): Unit = {
try jsonWriter.write(a, tokenWriter) finally {
tokenWriter.flush()
Expand All @@ -43,6 +47,10 @@ package object tethys {
producer.fromReader(reader).readJson[A]
}

def readJsonWith[A](jsonReader: JsonReader[A])(implicit producer: TokenIteratorProducer): Either[ReaderError, A] = {
readJson[A](jsonReader, producer)
}

def toTokenIterator(implicit producer: TokenIteratorProducer): TokenIterator = {
producer.fromReader(reader)
}
Expand Down
Loading

0 comments on commit 118af70

Please sign in to comment.