Skip to content

Commit

Permalink
Fix "diverging implicit expansion" error with Scala 2 (#1311)
Browse files Browse the repository at this point in the history
  • Loading branch information
plokhotnyuk authored Feb 12, 2025
1 parent 323975d commit d027fad
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 1 deletion.
8 changes: 7 additions & 1 deletion project/BuildHelper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,13 @@ object BuildHelper {
mimaBinaryIssueFilters ++= Seq(
exclude[Problem]("zio.json.internal.*"),
exclude[Problem]("zio.json.yaml.internal.*")
),
) ++ (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, _)) =>
Seq(
exclude[Problem]("zio.json.JsonFieldDecoder.stringLike") // FIXME: remove after v0.7.19 release
)
case _ => Seq.empty
}),
mimaFailOnProblem := true
)

Expand Down
91 changes: 91 additions & 0 deletions zio-json/shared/src/main/scala-2.x/zio/json/JsonFieldDecoder.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2019-2022 John A. De Goes and the ZIO Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package zio.json

import zio.json.internal.Lexer
import zio.json.uuid.UUIDParser

/** When decoding a JSON Object, we only allow the keys that implement this interface. */
trait JsonFieldDecoder[+A] {
self =>

final def map[B](f: A => B): JsonFieldDecoder[B] =
new JsonFieldDecoder[B] {

def unsafeDecodeField(trace: List[JsonError], in: String): B =
f(self.unsafeDecodeField(trace, in))
}

final def mapOrFail[B](f: A => Either[String, B]): JsonFieldDecoder[B] =
new JsonFieldDecoder[B] {

def unsafeDecodeField(trace: List[JsonError], in: String): B =
f(self.unsafeDecodeField(trace, in)) match {
case Left(err) => Lexer.error(err, trace)
case Right(b) => b
}
}

def unsafeDecodeField(trace: List[JsonError], in: String): A
}

object JsonFieldDecoder extends LowPriorityJsonFieldDecoder {
def apply[A](implicit a: JsonFieldDecoder[A]): JsonFieldDecoder[A] = a

implicit val string: JsonFieldDecoder[String] = new JsonFieldDecoder[String] {
def unsafeDecodeField(trace: List[JsonError], in: String): String = in
}

implicit val int: JsonFieldDecoder[Int] = new JsonFieldDecoder[Int] {
def unsafeDecodeField(trace: List[JsonError], in: String): Int =
try in.toInt
catch {
case _: NumberFormatException => Lexer.error(s"Invalid Int: ${strip(in)}", trace)
}
}

implicit val long: JsonFieldDecoder[Long] = new JsonFieldDecoder[Long] {
def unsafeDecodeField(trace: List[JsonError], in: String): Long =
try in.toLong
catch {
case _: NumberFormatException => Lexer.error(s"Invalid Long: ${strip(in)}", trace)
}
}

implicit val uuid: JsonFieldDecoder[java.util.UUID] = new JsonFieldDecoder[java.util.UUID] {
def unsafeDecodeField(trace: List[JsonError], in: String): java.util.UUID =
try UUIDParser.unsafeParse(in)
catch {
case _: IllegalArgumentException => Lexer.error(s"Invalid UUID: ${strip(in)}", trace)
}
}

// use this instead of `string.mapOrFail` in supertypes (to prevent class initialization error at runtime)
private[json] def mapStringOrFail[A](f: String => Either[String, A]): JsonFieldDecoder[A] =
new JsonFieldDecoder[A] {
def unsafeDecodeField(trace: List[JsonError], in: String): A =
f(string.unsafeDecodeField(trace, in)) match {
case Left(err) => Lexer.error(err, trace)
case Right(value) => value
}
}

private[json] def strip(s: String, len: Int = 50): String =
if (s.length <= len) s
else s.substring(0, len) + "..."
}

private[json] trait LowPriorityJsonFieldDecoder
12 changes: 12 additions & 0 deletions zio-json/shared/src/test/scala/zio/json/DecoderSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -930,4 +930,16 @@ object DecoderSpec extends ZIOSpecDefault {
implicit val eventDecoder: JsonDecoder[Event] = DeriveJsonDecoder.gen[Event]
implicit val eventEncoder: JsonEncoder[Event] = DeriveJsonEncoder.gen[Event]
}

object fieldDecoder {
case class PersonId(value: String)

object PersonId {
implicit val jsonFieldEncoder: JsonFieldEncoder[PersonId] = JsonFieldEncoder.string.contramap(_.value)
implicit val jsonFieldDecoder: JsonFieldDecoder[PersonId] = JsonFieldDecoder.string.map(PersonId.apply)
}

implicitly[JsonFieldEncoder[PersonId]]
implicitly[JsonFieldDecoder[PersonId]]
}
}

0 comments on commit d027fad

Please sign in to comment.