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

com.rojoma.json.v3.util.JsonArrayIterator.scala Maven / Gradle / Ivy

The newest version!
package com.rojoma.json.v3
package util

import codec._
import io._
import `-impl`.util.AbstractIterator

import java.io.Reader

/** Helper for reading lazily reading objects out of a source of
 * `JsonEvent`s representing a JSON array.  Calling `hasNext` can throw
 * any `JsonLexException`.  Calling `next()` can throw any JSON lex or parse
 * exception, or `ElementDecodeException` if the data in the array cannot be
 * decoded as a `T` at that point.  In the latter case, the iterator is still
 * valid and positioned as if the decode had succeeded so it can continue to
 * be used.
 *
 * @param input A source of JSON events
 * @param alreadyInArray A flag to indicate the start-of-array event has already been consumed (default false)
 * @return An iterator of `T`s
 * @throws JsonLexException if `alreadyInArray` is false and a lexing exception or EOF occurs.
 * @throws JsonBadParse if `alreadyInArray` is false and the first event is not a `StartOfArrayEvent`
 */
object JsonArrayIterator {
  def fromReader[T : JsonDecode](reader: Reader, alreadyInArray: Boolean = false, buffer: Boolean = true): Iterator[T] = {
    val events =
      if(buffer) new FusedBlockJsonEventIterator(reader)
      else new JsonEventIterator(reader)
    fromEvents(events, alreadyInArray)
  }

  @deprecated(message = "Prefer fromEvents", since = "3.5.0")
  def apply[T : JsonDecode](input: Iterator[JsonEvent], alreadyInArray: Boolean = false): Iterator[T] =
    fromEvents[T](input, alreadyInArray)

  def fromEvents[T : JsonDecode](input: Iterator[JsonEvent], alreadyInArray: Boolean = false): Iterator[T] = {
    val buffer = input.buffered
    var item = 0

    if(!alreadyInArray) {
      val next = try {
        buffer.next()
      } catch {
        case nst: NoSuchTokenException => throw new JsonParserEOF(nst.position)
        case _: NoSuchElementException => throw new JsonParserEOF(Position.Invalid)
      }
      if(!next.isInstanceOf[StartOfArrayEvent]) throw new JsonBadParse(next)
    }

    new AbstractIterator[T] {
      private var done = false

      def hasNext: Boolean = {
        if(done) return false
        val head = try {
          buffer.head
        } catch {
          case nst: NoSuchTokenException => throw new JsonParserEOF(nst.position)
          case _: NoSuchElementException => throw new JsonParserEOF(Position.Invalid)
        }
        if(head.isInstanceOf[EndOfArrayEvent]) {
          buffer.next()
          done = true
          return false
        }
        true
      }

      def next(): T = {
        if(!hasNext) Iterator.empty.next()
        val pos = buffer.head.position
        item += 1
        JsonDecode.fromJValue[T](JsonReader.fromEvents(buffer)) match {
          case Right(res) => res
          case Left(err) => throw new ElementDecodeException(pos, err.augment(Path.Index(item - 1)))
        }
      }
    }
  }

  class ElementDecodeException(val position: Position, val error: DecodeError) extends RuntimeException((if (position.isValid) position + ": " else "") + error.english)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy