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

format.specific.matchers.DefaultValueMatcher.scala Maven / Gradle / Ivy

There is a newer version: 1.0.0-RC23
Show newest version
package avrohugger
package format
package specific
package matchers

import treehugger.forest._
import definitions._
import treehuggerDSL._

import org.apache.avro.Schema

import org.codehaus.jackson.JsonNode
import org.codehaus.jackson.map.ObjectMapper
import org.codehaus.jackson.node.{NullNode, ObjectNode, TextNode}

import scala.collection.JavaConversions._

object DefaultValueMatcher {
  
  // This code was stolen from here:
  // https://github.com/julianpeeters/avro-scala-macro-annotations/blob/104fa325a00044ff6d31184fa7ff7b6852e9acd5/macros/src/main/scala/avro/scala/macro/annotations/provider/matchers/FromJsonMatcher.scala
  def getDefaultValue(field: Schema.Field, typeMatcher: TypeMatcher): Tree = {

    val nullNode = new TextNode("null")

    def fromJsonNode(node: JsonNode, schema: Schema): Tree = {
      schema.getType match {
        case _ if node == null => EmptyTree //not `default=null`, but no default
        case Schema.Type.INT => LIT(node.getIntValue)
        case Schema.Type.FLOAT => LIT(node.getDoubleValue.asInstanceOf[Float])
        case Schema.Type.LONG => LIT(node.getLongValue)
        case Schema.Type.DOUBLE => LIT(node.getDoubleValue)
        case Schema.Type.BOOLEAN => LIT(node.getBooleanValue)
        case Schema.Type.STRING => LIT(node.getTextValue)

        case Schema.Type.ENUM => (REF(schema.getName) DOT node.getTextValue)
        case Schema.Type.NULL => LIT(null)
        case Schema.Type.UNION => {
          val unionSchemas = schema.getTypes.toList
          if (unionSchemas.length == 2 &&
            unionSchemas.exists(schema => schema.getType == Schema.Type.NULL) &&
            unionSchemas.exists(schema => schema.getType != Schema.Type.NULL)) {
            val maybeSchema = unionSchemas.find(schema => schema.getType != Schema.Type.NULL)
            maybeSchema match {
              case Some(unionSchema) => {
                node match {
                  case `nullNode` => NONE
                  case nn: NullNode => NONE
                  case nonNullNode => SOME(fromJsonNode(nonNullNode, unionSchema))
                }
              }
              case None => throw new Exception("no avro type found in this union")
            }
          }
          else throw new Exception("Unsupported union field")
        }
        case Schema.Type.ARRAY => {
          val maybeCustom = typeMatcher.typeMap.get("array")
          val collectionType = {
            DefaultParamMatcher.checkCustomArrayType(maybeCustom, ListClass)
          }
          collectionType APPLY(node.getElements.toSeq.map(e => fromJsonNode(e, schema.getElementType)))
        }
        case Schema.Type.MAP => {
          val kvps = node.getFields.toList.map(e => LIT(e.getKey) ANY_-> fromJsonNode(e.getValue, schema.getValueType))
          MAKE_MAP(kvps)
        }
        case Schema.Type.RECORD  => {
          val fields  = schema.getFields
          val jsObject = node match {
            case t: TextNode =>
              val mapper = new ObjectMapper();
              mapper.readValue(t.getTextValue, classOf[ObjectNode])
            case o: ObjectNode => o
            case _ => throw new Exception(s"Invalid default value for field: $field, value: $node")
          }

          val fieldValues = fields.map { f =>
            fromJsonNode(jsObject.get(f.name), f.schema)
          }
          NEW(schema.getName, fieldValues: _*)
        }
        case x => throw new Exception("Can't extract a default field, type not yet supported: " + x)
      }
    }

    fromJsonNode(field.defaultValue, field.schema)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy