Skip to content

Commit

Permalink
Merge pull request #293 from Pashtetost/java-time-reader-writer
Browse files Browse the repository at this point in the history
JsonWriter and JsonReader for java.time
  • Loading branch information
dos65 authored May 28, 2024
2 parents 236b8e3 + 27eb697 commit 46a966d
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 2 deletions.
24 changes: 24 additions & 0 deletions modules/core/src/main/scala/tethys/readers/KeyReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,28 @@ object KeyReader {
implicit lazy val longKeyReader: KeyReader[Long] = new KeyReader[Long] {
override def read(s: String)(implicit fieldName: FieldName): Long = s.toLong
}

implicit lazy val instantKeyReader: KeyReader[java.time.Instant] = new KeyReader[java.time.Instant] {
override def read(s: String)(implicit fieldName: FieldName): java.time.Instant = java.time.Instant.parse(s)
}

implicit lazy val localDateKeyReader: KeyReader[java.time.LocalDate] = new KeyReader[java.time.LocalDate] {
override def read(s: String)(implicit fieldName: FieldName): java.time.LocalDate =
java.time.LocalDate.parse(s, java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)
}

implicit lazy val localDateTimeKeyReader: KeyReader[java.time.LocalDateTime] = new KeyReader[java.time.LocalDateTime] {
override def read(s: String)(implicit fieldName: FieldName): java.time.LocalDateTime =
java.time.LocalDateTime.parse(s, java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)
}

implicit lazy val offsetDateTimeKeyReader: KeyReader[java.time.OffsetDateTime] = new KeyReader[java.time.OffsetDateTime] {
override def read(s: String)(implicit fieldName: FieldName): java.time.OffsetDateTime =
java.time.OffsetDateTime.parse(s, java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)
}

implicit lazy val zonedDateTimeKeyReader: KeyReader[java.time.ZonedDateTime] = new KeyReader[java.time.ZonedDateTime] {
override def read(s: String)(implicit fieldName: FieldName): java.time.ZonedDateTime =
java.time.ZonedDateTime.parse(s, java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,14 @@ trait AllJsonReaders extends OptionReaders {
implicit lazy val javaBigIntegerReader: JsonReader[java.math.BigInteger] = bigIntReader.map(_.bigInteger)
implicit lazy val javaUUIDReader: JsonReader[java.util.UUID] = stringReader.map(java.util.UUID.fromString(_))

implicit lazy val javaInstantReader: JsonReader[java.time.Instant] = stringReader.map(java.time.Instant.parse)
implicit lazy val javaLocalDateReader: JsonReader[java.time.LocalDate] =
stringReader.map(java.time.LocalDate.parse(_, java.time.format.DateTimeFormatter.ISO_LOCAL_DATE))
implicit lazy val javaLocalDateTimeReader: JsonReader[java.time.LocalDateTime] =
stringReader.map(java.time.LocalDateTime.parse(_, java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME))
implicit lazy val javaOffsetDateTimeReader: JsonReader[java.time.OffsetDateTime] =
stringReader.map(java.time.OffsetDateTime.parse(_, java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME))
implicit lazy val javaZonedDateTimeReader: JsonReader[java.time.ZonedDateTime] =
stringReader.map(java.time.ZonedDateTime.parse(_, java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME))

}
15 changes: 15 additions & 0 deletions modules/core/src/main/scala/tethys/writers/KeyWriter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,19 @@ object KeyWriter {
implicit lazy val intKeyWriter: KeyWriter[Int] = _.toString

implicit lazy val longKeyWriter: KeyWriter[Long] = _.toString

implicit lazy val instantKeyWriter: KeyWriter[java.time.Instant] = _.toString

implicit lazy val localDateKeyWriter: KeyWriter[java.time.LocalDate] =
_.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)

implicit lazy val localDateTimeKeyWriter: KeyWriter[java.time.LocalDateTime] =
_.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)

implicit lazy val offsetDateTimeKeyWriter
: KeyWriter[java.time.OffsetDateTime] =
_.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)

implicit lazy val zonedDateTimeKeyWriter: KeyWriter[java.time.ZonedDateTime] =
_.format(java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME)
}
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,34 @@ trait AllJsonWriters extends OptionWriters with EitherWriters {
implicit lazy val nullWriter: JsonWriter[Null] = new JsonWriter[Null] {
override def write(value: Null, tokenWriter: TokenWriter): Unit = tokenWriter.writeNull()
}

implicit lazy val instantWriter: JsonWriter[java.time.Instant] =
new JsonWriter[java.time.Instant] {
override def write(value: java.time.Instant, tokenWriter: TokenWriter): Unit =
tokenWriter.writeString(value.toString)
}

implicit lazy val localDateWriter: JsonWriter[java.time.LocalDate] =
new JsonWriter[java.time.LocalDate] {
override def write(value: java.time.LocalDate, tokenWriter: TokenWriter): Unit =
tokenWriter.writeString(value.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE))
}

implicit lazy val localDateTimeWriter: JsonWriter[java.time.LocalDateTime] =
new JsonWriter[java.time.LocalDateTime] {
override def write(value: java.time.LocalDateTime, tokenWriter: TokenWriter): Unit =
tokenWriter.writeString(value.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME))
}

implicit lazy val offsetDateTimeWriter: JsonWriter[java.time.OffsetDateTime] =
new JsonWriter[java.time.OffsetDateTime] {
override def write(value: java.time.OffsetDateTime, tokenWriter: TokenWriter): Unit =
tokenWriter.writeString(value.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME))
}

implicit lazy val zonedDateTimeWriter: JsonWriter[java.time.ZonedDateTime] =
new JsonWriter[java.time.ZonedDateTime] {
override def write(value: java.time.ZonedDateTime, tokenWriter: TokenWriter): Unit =
tokenWriter.writeString(value.format(java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import scala.reflect.ClassTag

class DefaultReadersTest extends AnyFlatSpec {
private val randomUUID = java.util.UUID.randomUUID()
private val instantNow = java.time.Instant.now()
private val localDateNow = java.time.LocalDate.now()
private val localDateTimeNow = java.time.LocalDateTime.now()
private val offsetDateTimeNow = java.time.OffsetDateTime.now()
private val zonedDateTimeNow = java.time.ZonedDateTime.now()

private def test[A](result: A)(implicit jsonReader: JsonReader[A], ct: ClassTag[A]): TestDefinition[A] = {
TestDefinition(result, jsonReader, ct.toString())
Expand All @@ -38,6 +43,15 @@ class DefaultReadersTest extends AnyFlatSpec {
test(List[Int](), "Seq.empty") -> arr(),
test(Map("a" -> 1, "b" -> 2)) -> obj("a" -> 1, "b" -> 2),
test(Map(randomUUID -> 1),"Map with UUID keys") -> obj(randomUUID.toString -> 1),
test(Map(instantNow -> 1), "Map with Instant keys") -> obj(instantNow.toString -> 1),
test(Map(localDateNow -> 1), "Map with LocalDate keys") ->
obj(localDateNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE) -> 1),
test(Map(localDateTimeNow -> 1), "Map with LocalDateTime keys") ->
obj(localDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME) -> 1),
test(Map(offsetDateTimeNow -> 1), "Map with OffsetDateTime keys") ->
obj(offsetDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME) -> 1),
test(Map(zonedDateTimeNow -> 1), "Map with ZonedDateTime keys") ->
obj(zonedDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME) -> 1),
test(Map(1L -> 1), "Map with Long keys") -> obj("1" -> 1),
test(Map(1 -> 1), "Map with Int keys") -> obj("1" -> 1),
test(Option(1), "Option.nonEmpty") -> value(1),
Expand All @@ -50,7 +64,12 @@ class DefaultReadersTest extends AnyFlatSpec {
test(1d: java.lang.Double) -> value(1d),
test(java.math.BigDecimal.valueOf(1)) -> value(1: BigDecimal),
test(java.math.BigInteger.valueOf(1)) -> value(1: BigInt),
test(randomUUID) -> value(randomUUID.toString)
test(randomUUID) -> value(randomUUID.toString),
test(instantNow) -> value(instantNow.toString),
test(localDateNow) -> value(localDateNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)),
test(localDateTimeNow) -> value(localDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)),
test(offsetDateTimeNow) -> value(offsetDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)),
test(zonedDateTimeNow) -> value(zonedDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME))
)

behavior of "Default readers"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import scala.reflect.ClassTag

class DefaultWritersTest extends AnyFlatSpec {
private val randomUUID = java.util.UUID.randomUUID()
private val instantNow = java.time.Instant.now()
private val localDateNow = java.time.LocalDate.now()
private val localDateTimeNow = java.time.LocalDateTime.now()
private val offsetDateTimeNow = java.time.OffsetDateTime.now()
private val zonedDateTimeNow = java.time.ZonedDateTime.now()

private def test[A](value: A)(implicit jsonWriter: JsonWriter[A], ct: ClassTag[A]): TestDefinition[A] = {
TestDefinition(value, jsonWriter, ct.toString())
Expand Down Expand Up @@ -40,6 +45,15 @@ class DefaultWritersTest extends AnyFlatSpec {
test(Map(randomUUID -> 1),"Map with UUID keys") -> obj(randomUUID.toString -> 1),
test(Map(1L -> 1), "Map with Long keys") -> obj("1" -> 1),
test(Map(1 -> 1), "Map with Int keys") -> obj("1" -> 1),
test(Map(instantNow -> 1), "Map with Instant keys") -> obj(instantNow.toString -> 1),
test(Map(localDateNow -> 1), "Map with LocalDate keys") ->
obj(localDateNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE) -> 1),
test(Map(localDateTimeNow -> 1), "Map with LocalDateTime keys") ->
obj(localDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME) -> 1),
test(Map(offsetDateTimeNow -> 1), "Map with OffsetDateTime keys") ->
obj(offsetDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME) -> 1),
test(Map(zonedDateTimeNow -> 1), "Map with ZonedDateTime keys") ->
obj(zonedDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME) -> 1),
test(Option(1), "Option.nonEmpty") -> value(1),
test(Option.empty[Int], "Option.empty") -> List(NullValueNode),
test(Right(1): Either[String, Int], "Either.right") -> value(1),
Expand All @@ -52,7 +66,12 @@ class DefaultWritersTest extends AnyFlatSpec {
test(1d: java.lang.Double) -> value(1d),
test(java.math.BigDecimal.valueOf(1)) -> value(1: BigDecimal),
test(java.math.BigInteger.valueOf(1)) -> value(1: BigInt),
test(randomUUID) -> value(randomUUID.toString)
test(randomUUID) -> value(randomUUID.toString),
test(instantNow) -> value(instantNow.toString),
test(localDateNow) -> value(localDateNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE)),
test(localDateTimeNow) -> value(localDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)),
test(offsetDateTimeNow) -> value(offsetDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME)),
test(zonedDateTimeNow) -> value(zonedDateTimeNow.format(java.time.format.DateTimeFormatter.ISO_ZONED_DATE_TIME))
)

behavior of "Default writers"
Expand Down

0 comments on commit 46a966d

Please sign in to comment.