All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.circe.Error.scala Maven / Gradle / Ivy

The newest version!
package io.circe

import cats.{ Eq, Show }
import cats.data.NonEmptyList

/**
 * The base exception type for both decoding and parsing errors.
 */
sealed abstract class Error extends Exception {
  final override def fillInStackTrace(): Throwable = this
}

/**
 * A convenience exception type for aggregating one or more decoding or parsing
 * errors.
 */
final case class Errors(errors: NonEmptyList[Error]) extends Exception {
  def toList: List[Error] = errors.head :: errors.tail

  override def fillInStackTrace(): Throwable = this
}

/**
 * An exception representing a parsing failure and wrapping the exception
 * provided by the parsing library.
 */
final case class ParsingFailure(message: String, underlying: Throwable) extends Error {
  final override def getMessage: String = message
}

object ParsingFailure {
  implicit final val eqParsingFailure: Eq[ParsingFailure] = Eq.instance {
    case (ParsingFailure(m1, t1), ParsingFailure(m2, t2)) => m1 == m2 && t1 == t2
  }

  implicit final val showParsingFailure: Show[ParsingFailure] = Show.show { failure =>
    s"ParsingFailure: ${failure.message}"
  }
}

/**
 * An exception representing a decoding failure and (lazily) capturing the
 * decoding history resulting in the failure.
 */
sealed abstract class DecodingFailure(val message: String) extends Error {
  def history: List[CursorOp]

  final override def getMessage: String =
    if (history.isEmpty) message else s"$message: ${history.mkString(",")}"

  final def copy(message: String = message, history: => List[CursorOp] = history): DecodingFailure = {
    def newHistory = history
    new DecodingFailure(message) {
      final lazy val history: List[CursorOp] = newHistory
    }
  }

  final def withMessage(message: String): DecodingFailure = copy(message = message)

  override final def toString: String = s"DecodingFailure($message, $history)"
  override final def equals(that: Any): Boolean = that match {
    case other: DecodingFailure => DecodingFailure.eqDecodingFailure.eqv(this, other)
    case _                      => false
  }
  override final def hashCode: Int = message.hashCode
}

object DecodingFailure {
  def apply(message: String, ops: => List[CursorOp]): DecodingFailure = new DecodingFailure(message) {
    final lazy val history: List[CursorOp] = ops
  }

  def unapply(error: Error): Option[(String, List[CursorOp])] = error match {
    case ParsingFailure(_, _)   => None
    case other: DecodingFailure => Some((other.message, other.history))
  }

  def fromThrowable(t: Throwable, ops: => List[CursorOp]): DecodingFailure = t match {
    case (d: DecodingFailure) => d
    case other =>
      val sw = new java.io.StringWriter
      val pw = new java.io.PrintWriter(sw)
      other.printStackTrace(pw)
      DecodingFailure(sw.toString, ops)
  }

  implicit final val eqDecodingFailure: Eq[DecodingFailure] = Eq.instance {
    case (DecodingFailure(m1, h1), DecodingFailure(m2, h2)) => m1 == m2 && CursorOp.eqCursorOpList.eqv(h1, h2)
  }

  /**
   * Creates compact, human readable string representations for DecodingFailure
   * Cursor history is represented as JS style selections, i.e. ".foo.bar[3]"
   */
  implicit final val showDecodingFailure: Show[DecodingFailure] = Show.show { failure =>
    val path = CursorOp.opsToPath(failure.history)
    s"DecodingFailure at ${path}: ${failure.message}"
  }
}

object Error {
  implicit final val eqError: Eq[Error] = Eq.instance {
    case (pf1: ParsingFailure, pf2: ParsingFailure)   => ParsingFailure.eqParsingFailure.eqv(pf1, pf2)
    case (df1: DecodingFailure, df2: DecodingFailure) => DecodingFailure.eqDecodingFailure.eqv(df1, df2)
    case (_, _)                                       => false
  }

  implicit final val showError: Show[Error] = Show.show {
    case pf: ParsingFailure  => ParsingFailure.showParsingFailure.show(pf)
    case df: DecodingFailure => DecodingFailure.showDecodingFailure.show(df)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy