tethys-json4s


License

License

Categories

Categories

JSON Data
GroupId

GroupId

com.tethys-json
ArtifactId

ArtifactId

tethys-json4s_2.11
Last Version

Last Version

0.11.0
Release Date

Release Date

Type

Type

jar
Description

Description

tethys-json4s
tethys-json4s
Project URL

Project URL

https://github.com/tethys-json/tethys
Project Organization

Project Organization

com.tethys-json
Source Code Management

Source Code Management

https://github.com/tethys-json/tethys

Download tethys-json4s_2.11

How to add to project

<!-- https://jarcasting.com/artifacts/com.tethys-json/tethys-json4s_2.11/ -->
<dependency>
    <groupId>com.tethys-json</groupId>
    <artifactId>tethys-json4s_2.11</artifactId>
    <version>0.11.0</version>
</dependency>
// https://jarcasting.com/artifacts/com.tethys-json/tethys-json4s_2.11/
implementation 'com.tethys-json:tethys-json4s_2.11:0.11.0'
// https://jarcasting.com/artifacts/com.tethys-json/tethys-json4s_2.11/
implementation ("com.tethys-json:tethys-json4s_2.11:0.11.0")
'com.tethys-json:tethys-json4s_2.11:jar:0.11.0'
<dependency org="com.tethys-json" name="tethys-json4s_2.11" rev="0.11.0">
  <artifact name="tethys-json4s_2.11" type="jar" />
</dependency>
@Grapes(
@Grab(group='com.tethys-json', module='tethys-json4s_2.11', version='0.11.0')
)
libraryDependencies += "com.tethys-json" % "tethys-json4s_2.11" % "0.11.0"
[com.tethys-json/tethys-json4s_2.11 "0.11.0"]

Dependencies

compile (3)

Group / Artifact Type Version
org.scala-lang : scala-library jar 2.11.12
com.tethys-json : tethys-core_2.11 jar 0.11.0
org.json4s : json4s-core_2.11 jar 3.6.7

test (1)

Group / Artifact Type Version
org.scalatest : scalatest_2.11 jar 3.1.0-SNAP13

Project Modules

There are no modules declared in this project.
CI Release
Build Status Maven Central

tethys

tethys is a JSON parsing/writing library for Scala

benchmarks

see here

Quick start

Add dependencies to your build.sbt

val tethysVersion = "latest version in badge"
libraryDependencies ++= Seq(
  "com.tethys-json" %% "tethys-core" % tethysVersion,
  "com.tethys-json" %% "tethys-jackson" % tethysVersion,
  "com.tethys-json" %% "tethys-derivation" % tethysVersion
)

or just

libraryDependecies ++= Seq(
  "com.tethys-json" %% "tethys" % "latest version in badge"
)

Also, tethys has the following integrations:

Circe

see project page

libraryDependencies += "com.tethys-json" %% "tethys-circe" % tethysVersion

Json4s

see project page

libraryDependencies += "com.tethys-json" %% "tethys-json4s" % tethysVersion

Enumeratum

see project page

libraryDependencies += "com.tethys-json" %% "tethys-enumeratum" % tethysVersion

core

core module contains all type classes for parsing/writing JSON. JSON string parsing/writing and derivation are separated to tethys-jackson and tethys-derivation

JsonWriter

JsonWriter writes json tokens to TokenWriter

import tethys._
import tethys.jackson._

List(1, 2, 3, 4).asJson

//or write directly to TokenWriter

val tokenWriter = YourWriter

tokenWriter.writeJson(List(1, 2, 3, 4))

New writers can be created with an object builder or with a combination of a few writers

import tethys._
import tethys.jackson._
import scala.reflect.ClassTag

case class Foo(bar: Int)

def classWriter[A](implicit ct: ClassTag[A]): JsonObjectWriter[A] = {
    JsonWriter.obj[A].addField("clazz")(_ => ct.toString())
}

implicit val fooWriter: JsonObjectWriter[Foo] = {
  classWriter[Foo] ++ JsonWriter.obj[Foo].addField("bar")(_.bar)
}

Foo(1).asJson

or just using another JsonWriter

import tethys._

case class Foo(bar: Int)

JsonWriter.stringWriter.contramap[Foo](_.bar.toString)

JsonReader

JsonReader converts a json token from TokenIterator to its value

import tethys._
import tethys.jackson._

"[1, 2, 3, 4]".jsonAs[List[Int]]

New readers can be created with a builder

import tethys._
import tethys.jackson._

case class Foo(bar: Int)

implicit val fooReader: JsonReader[Foo] = JsonReader.builder
    .addField[Int]("bar")
    .buildReader(Foo.apply)
    
"""{"bar":1}""".jsonAs[Foo]

Also you can select an existing reader that depends on other json fields

import tethys._
import tethys.jackson._

trait FooBar
case class Foo(foo: Int) extends FooBar
case class Bar(bar: String)  extends FooBar

val fooReader: JsonReader[Foo] = JsonReader.builder
    .addField[Int]("foo")
    .buildReader(Foo.apply)
    
val barReader: JsonReader[Bar] = JsonReader.builder
    .addField[String]("bar")
    .buildReader(Bar.apply)
    
implicit val fooBarReader: JsonReader[FooBar] = JsonReader.builder
    .addField[String]("clazz")
    .selectReader[FooBar] {
      case "Foo" => fooReader
      case _ => barReader 
    }    
    
"""{"clazz":"Foo","foo":1}""".jsonAs[FooBar]

Please check out tethys package object for all available syntax Ops classes

derivation

tethys-derivation provides semiauto and auto macro derivation JsonReader and JsonWriter instances.
In most cases you should prefer semiauto derivation because it's more precise, faster in compilation and flexible.

import tethys._
import tethys.jackson._
import tethys.derivation.auto._
import tethys.derivation.semiauto._

case class Foo(bar: Bar)
case class Bar(seq: Seq[Int])

implicit val barWriter: JsonObjectWriter[Bar] = jsonWriter[Bar] //semiauto
implicit val barReader: JsonReader[Bar] = jsonReader[Bar]

"""{"bar":{"seq":[1,2,3]}}""".jsonAs[Foo] //Foo reader auto derived

In complex cases you can provide some additional information to jsonWriter and jsonReader functions

import tethys._
import tethys.derivation.builder._
import tethys.derivation.semiauto._

case class Foo(a: Int, b: String, c: Any, d: Boolean, e: Double)

implicit val fooWriter = jsonWriter[Foo] {
  describe {
    //Any functions are allowed in lambdas
    WriterBuilder[Foo]
      .remove(_.b)
      .add("d")(_.b.trim)
      .update(_.a)(_ + 1)
      // the only way to semiauto derive Any
      // this partial function will be replaced with match in the final writer
      .updatePartial(_.c) {  
        case s: String => s
        case i: Int if i % 2 == 0 => i / 2
        case i: Int => i + 1
        case other => other.toString 
      }
      .update(_.d).fromRoot(foo => if(foo.d) foo.a else foo.a / 2) //same as update but function accepts root element
      .updatePartial(_.e).fromRoot { //same as updatePartial but function accepts root element
        case Foo(1, _, _, _, e) => e
        case Foo(2, _, _, _, e) => e % 2
        case foo => e.toString
      }
  }
}

implicit val fooReader = jsonReader[Foo] {
    //Any functions are allowed in lambdas
    ReaderBuilder[Foo]
      .extractReader(_.c).from(_.a)('otherField.as[String]) { // provide reader for Any field
        case (1, "str") => JsonReader[String]
        case (_, "int") => JsonReader[Int]
        case _ => JsonReader[Option[Boolean]]
      }
      .extract(_.a).from(_.b).and("otherField2".as[Int])((b, other) => d.toInt + other) // calculate a field that depends on other fields
      .extract(_.e).as[Option[Double]](_.getOrElse(1.0)) // extract a field from a value of a specific type
}

jackson

tethys-jackson module provides bridge instances for jackson streaming api

import tethys.jackson._
//import tethys.jackson.pretty._ //pretty writing

//that's it. welcome to use jackson

complex case

import tethys._
import tethys.jackson._
import tethys.derivation.auto._

case class Foo(bar: Bar)
case class Bar(seq: Seq[Int])

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

AST support

In some cases, you may need to work with raw AST, so tethys can offer you circe and json4s AST support:

circe AST support

import tethys._
import tethys.jackson._
import tethys.derivation.auto._
import tethys.circe._

import io.circe.Json

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

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

foo.bar // 1: Int
foo.baz // [ "some", { "arbitrary" : "json" } ]: io.circe.Json

json4s AST support

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"))))

enumeratum support

enumeratum module provides bunch of mixins for your Enum classes.

import enumeratum.{Enum, EnumEntry}
import tethys.enumeratum._

sealed trait Direction extends EnumEntry
case object Direction extends Enum[Direction] 
  with TethysEnum[Direction] // provides JsonReader and JsonWriter instances 
  with TethysKeyEnum[Direction] { // provides KeyReader and KeyWriter instances
  
  
  case object Up extends    Direction
  case object Down extends  Direction
  case object Left extends  Direction
  case object Right extends Direction

  val values = findValues
}

Versions

Version
0.11.0
0.10.0
0.9.0.1
0.9.0
0.8.0.1
0.8.0
0.7.0.2
0.7.0.1
0.7.0