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

com.dslplatform.json.runtime.OptionAnalyzer.scala Maven / Gradle / Ivy

The newest version!
package com.dslplatform.json
package runtime

import java.lang.reflect.{ParameterizedType, Type}

object OptionAnalyzer {

	val Reader: DslJson.ConverterFactory[JsonReader.ReadObject[_]] = (manifest: Type, dslJson: DslJson[_]) => {
    manifest match {
      case pt: ParameterizedType if pt.getActualTypeArguments.length == 1 =>
        pt.getRawType match {
          case inner: Class[_] => analyzeDecoding(manifest, pt.getActualTypeArguments()(0), inner, dslJson).orNull
          case _ => null
        }
      case cl: Class[_] =>
        analyzeDecoding(manifest, classOf[AnyRef], cl, dslJson).orNull
      case _ => null
    }
  }

	val Writer: DslJson.ConverterFactory[JsonWriter.WriteObject[_]] = (manifest: Type, dslJson: DslJson[_]) => {
    manifest match {
      case pt: ParameterizedType if pt.getActualTypeArguments.length == 1 =>
        pt.getRawType match {
          case inner: Class[_] => analyzeEncoding(manifest, pt.getActualTypeArguments()(0), inner, dslJson).orNull
          case _ => null
        }
      case cl: Class[_] =>
        analyzeEncoding(manifest, classOf[AnyRef], cl, dslJson).orNull
      case _ => null
    }
	}

	private def analyzeDecoding(manifest: Type, content: Type, raw: Class[_], json: DslJson[_]): Option[OptionDecoder[_]] = {
    if (!classOf[Option[_]].isAssignableFrom(raw)) {
      None
    } else {
      content match {
        case opt: Class[_] if classOf[Option[_]].isAssignableFrom(opt) =>
          analyzeDecoding(content, classOf[AnyRef], classOf[Option[_]], json) match {
            case Some(nested) =>
              val outer = new OptionDecoder(nested)
              json.registerReader(manifest, outer)
              Some(outer)
            case _ => None
          }
        case _ =>
          Option(json.tryFindReader(content)) match {
            case Some(reader) =>
              val decoder = new OptionDecoder(reader)
              json.registerReader(manifest, decoder)
              Some(decoder)
            case _ => None
          }
      }
    }
  }

	private def analyzeEncoding(manifest: Type, content: Type, raw: Class[_], json: DslJson[_]): Option[JsonWriter.WriteObject[_]] = {
    if (!classOf[Option[_]].isAssignableFrom(raw)) {
      None
    } else {
      content match {
        case opt: Class[_] if classOf[Option[_]].isAssignableFrom(opt) =>
          analyzeEncoding(content, classOf[AnyRef], classOf[Option[_]], json) match {
            case Some(nested) =>
              json.registerWriter(manifest, nested)
              Some(nested)
            case _ => None
          }
        case _ =>
          val writer = if (classOf[AnyRef] eq content) None else Option(json.tryFindWriter(content))
          if ((classOf[AnyRef] ne content) && writer.isEmpty) {
            None
          } else if (writer.isEmpty || (content eq classOf[AnyRef])) {
            val encoder = new OptionUnknownEncoder(json)
            json.registerWriter(manifest, encoder)
            Some(encoder)
          } else {
            val encoder = new OptionKnownEncoder(json, writer.get)
            json.registerWriter(manifest, encoder)
            Some(encoder)
          }
      }
    }
  }

	private final class OptionDecoder[T](decoder: JsonReader.ReadObject[T]) extends JsonReader.ReadObject[Option[T]] {
		require (decoder ne null, "decoder can't be null")

		override def read(reader: JsonReader[_]): Option[T] = {
			if (reader.wasNull) None
			else Option(decoder.read(reader))
		}
	}

  private final class OptionKnownEncoder[T](json: DslJson[_], encoder: JsonWriter.WriteObject[T]) extends JsonWriter.WriteObject[Option[T]] {
    require(json ne null, "json can't be null")
    require(encoder ne null, "encoder can't be null")

    override def write(writer: JsonWriter, value: Option[T]): Unit = {
      if (value.isEmpty) writer.writeNull()
      else encoder.write(writer, value.get)
    }
  }

  private final class OptionUnknownEncoder[T](json: DslJson[_]) extends JsonWriter.WriteObject[Option[T]] {
    require(json ne null, "json can't be null")

    override def write(writer: JsonWriter, value: Option[T]): Unit = {
      if (value == null || value.isEmpty) writer.writeNull()
      else {
        val unpacked = value.get
        if (unpacked == null) writer.writeNull()
        else {
          val jw = json.tryFindWriter(unpacked.getClass).asInstanceOf[JsonWriter.WriteObject[T]]
          if (jw == null) throw new ConfigurationException(s"Unable to find writer for ${unpacked.getClass}")
          jw.write(writer, unpacked)
        }
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy