Serialization.scala 5.03 KB
Newer Older
Harish Butani committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

Harish Butani committed
19 20 21
package org.apache.metadata.json

import org.apache.metadata.types.DataTypes.{MapType, TypeCategory, ArrayType}
22
import org.apache.metadata.{ITypedStruct, IStruct, MetadataException, MetadataService}
Harish Butani committed
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
import org.apache.metadata.types._
import org.json4s.JsonAST.JInt
import org.json4s._
import org.json4s.native.Serialization.{read, write => swrite}
import org.json4s.reflect.{ScalaType, Reflector}
import java.util.regex.Pattern
import java.util.Date
import collection.JavaConversions._
import scala.collection.JavaConverters._

class BigDecimalSerializer extends CustomSerializer[java.math.BigDecimal](format => ( {
    case JDecimal(e) => e.bigDecimal
}, {
  case e: java.math.BigDecimal => JDecimal(new BigDecimal(e))
}
  ))

class BigIntegerSerializer extends CustomSerializer[java.math.BigInteger](format => ( {
  case JInt(e) => e.bigInteger
}, {
  case e: java.math.BigInteger => JInt(new BigInt(e))
}
  ))

47
class TypedStructSerializer extends Serializer[ITypedStruct] {
Harish Butani committed
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70

  def extractList(lT : ArrayType, value : JArray)(implicit format: Formats) : Any = {
    val dT = lT.getElemType
    value.arr.map(extract(dT, _)).asJava
  }

  def extractMap(mT : MapType, value : JObject)(implicit format: Formats) : Any = {
    val kT = mT.getKeyType
    val vT = mT.getValueType
    value.obj.map{f : JField => f._1 -> extract(vT, f._2) }.toMap.asJava
  }

  def extract(dT : IDataType[_], value : JValue)(implicit format: Formats) : Any = value match {
    case value : JBool => Extraction.extract[Boolean](value)
    case value : JInt => Extraction.extract[Int](value)
    case value : JDouble => Extraction.extract[Double](value)
    case value : JDecimal => Extraction.extract[BigDecimal](value)
    case value : JString => Extraction.extract[String](value)
    case JNull => null
    case value : JArray => extractList(dT.asInstanceOf[ArrayType], value.asInstanceOf[JArray])
    case value : JObject if dT.getTypeCategory eq TypeCategory.MAP =>
      extractMap(dT.asInstanceOf[MapType], value.asInstanceOf[JObject])
    case value : JObject  =>
71
      Extraction.extract[ITypedStruct](value)
Harish Butani committed
72 73 74
  }

  def deserialize(implicit format: Formats) = {
75
    case (TypeInfo(clazz, ptype), json) if classOf[ITypedStruct].isAssignableFrom(clazz) => json match {
Harish Butani committed
76 77 78
      case JObject(fs) =>
        val(typ, fields) = fs.partition(f => f._1 == Serialization.STRUCT_TYPE_FIELD_NAME)
        val typName = typ(0)._2.asInstanceOf[JString].s
Harish Butani committed
79 80
        val sT = MetadataService.getCurrentTypeSystem().getDataType(
          classOf[IConstructableType[IStruct, ITypedStruct]], typName).asInstanceOf[IConstructableType[IStruct, ITypedStruct]]
Harish Butani committed
81 82 83
        val s = sT.createInstance()
        fields.foreach { f =>
          val fName = f._1
84
          val fInfo = sT.fieldMapping.fields(fName)
Harish Butani committed
85 86 87
          if ( fInfo != null ) {
            //println(fName)
            var v = f._2
88 89
            if ( fInfo.dataType().getTypeCategory == TypeCategory.TRAIT ||
              fInfo.dataType().getTypeCategory == TypeCategory.STRUCT) {
Harish Butani committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
              v = v match {
                case JObject(sFields) =>
                  JObject(JField(Serialization.STRUCT_TYPE_FIELD_NAME, JString(fInfo.dataType.getName)) :: sFields)
                case x => x
              }
            }
            s.set(fName, extract(fInfo.dataType(), v))
          }
        }
        s
      case x => throw new MappingException("Can't convert " + x + " to TypedStruct")
    }

  }

  /**
   * Implicit conversion from `java.math.BigInteger` to `scala.BigInt`.
   * match the builtin conversion for BigDecimal.
   * See https://groups.google.com/forum/#!topic/scala-language/AFUamvxu68Q
   */
  //implicit def javaBigInteger2bigInt(x: java.math.BigInteger): BigInt = new BigInt(x)

  def serialize(implicit format: Formats) = {
113
    case e: ITypedStruct =>
114
      val fields  = e.fieldMapping.fields.map {
Harish Butani committed
115 116 117 118 119 120 121 122
        case (fName, info) => {
          var v = e.get(fName)
          if ( v != null && (info.dataType().getTypeCategory eq TypeCategory.MAP) ) {
            v = v.asInstanceOf[java.util.Map[_,_]].toMap
          }
          JField(fName, Extraction.decompose(v))
        }
      }.toList.map(_.asInstanceOf[JField])
123
      JObject(JField(Serialization.STRUCT_TYPE_FIELD_NAME, JString(e.getTypeName)) :: fields)
Harish Butani committed
124 125 126 127 128 129
  }
}

object Serialization {
  val STRUCT_TYPE_FIELD_NAME = "$typeName$"
}