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

jacks.module.scala Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2011 - Will Glozer.  All rights reserved.

package com.lambdaworks.jacks

import scala.collection._
import scala.collection.generic._
import scala.collection.mutable.PriorityQueue

import com.fasterxml.jackson.annotation._
import com.fasterxml.jackson.annotation.JsonInclude.Include
import com.fasterxml.jackson.annotation.JsonInclude.Include._

import com.fasterxml.jackson.core._
import com.fasterxml.jackson.databind._
import com.fasterxml.jackson.databind.deser._
import com.fasterxml.jackson.databind.ser._
import com.fasterxml.jackson.databind.`type`._

import java.lang.annotation.Annotation
import java.lang.reflect.{Constructor, Method}

import tools.scalap.scalax.rules.scalasig.ScalaSig

class ScalaModule extends Module {
  def version       = new Version(2, 1, 0, null, "com.lambdaworks", "jacks")
  def getModuleName = "ScalaModule"

  def setupModule(ctx: Module.SetupContext) {
    ctx.addSerializers(new ScalaSerializers)
    ctx.addDeserializers(new ScalaDeserializers)
  }
}

class ScalaDeserializers extends Deserializers.Base {
  override def findBeanDeserializer(t: JavaType, cfg: DeserializationConfig, bd: BeanDescription): JsonDeserializer[_] = {
    val cls = t.getRawClass

    if (classOf[GenTraversable[_]].isAssignableFrom(cls)) {
      if (classOf[GenSeq[_]].isAssignableFrom(cls)) {
        val c = companion[GenericCompanion[GenSeq]](cls)
        new SeqDeserializer[Any, GenSeq](c, t.containedType(0))
      } else if (classOf[SortedMap[_, _]].isAssignableFrom(cls)) {
        val c = companion[SortedMapFactory[SortedMap]](cls)
        val o = ordering(t.containedType(0))
        new SortedMapDeserializer[Any, Any](c, o, t.containedType(0), t.containedType(1))
      } else if (classOf[GenMap[_, _]].isAssignableFrom(cls)) {
        val c = companion[GenMapFactory[GenMap]](cls)
        new MapDeserializer[Any, Any](c, t.containedType(0), t.containedType(1))
      } else if (classOf[GenSet[_]].isAssignableFrom(cls)) {
        if (classOf[BitSet].isAssignableFrom(cls)) {
          val c = companion[BitSetFactory[BitSet]](cls)
          val t = cfg.getTypeFactory.constructType(classOf[Int])
          new BitSetDeserializer[BitSet](c, t)
        } else if (classOf[SortedSet[_]].isAssignableFrom(cls)) {
          val c = companion[SortedSetFactory[SortedSet]](cls)
          val o = ordering(t.containedType(0))
          new SortedSetDeserializer[Any, SortedSet](c, o, t.containedType(0))
        } else if (classOf[BitSet].isAssignableFrom(cls)) {
          val c = companion[BitSetFactory[BitSet]](cls)
          val t = cfg.getTypeFactory.constructType(classOf[Int])
          new BitSetDeserializer[BitSet](c, t)
        } else {
          val c = companion[GenericCompanion[GenSet]](cls)
          new SeqDeserializer[Any, GenSet](c, t.containedType(0))
        }
      } else if (classOf[PriorityQueue[_]].isAssignableFrom(cls)) {
        val c = companion[OrderedTraversableFactory[PriorityQueue]](cls)
        val o = ordering(t.containedType(0))
        new OrderedDeserializer[Any, PriorityQueue](c, o, t.containedType(0))
      } else {
        null
      }
    } else if (classOf[Option[_]].isAssignableFrom(cls)) {
      new OptionDeserializer(t.containedType(0))
    } else if (classOf[Product].isAssignableFrom(cls) && cls.getName.startsWith("scala.Tuple")) {
      new TupleDeserializer(t)
    } else if (classOf[Product].isAssignableFrom(cls)) {
      ScalaTypeSig(cfg.getTypeFactory, t) match {
        case Some(sts) if sts.isCaseClass => new CaseClassDeserializer(t, sts.creator)
        case _                            => null
      }
    } else if (classOf[Symbol].isAssignableFrom(cls)) {
      new SymbolDeserializer
    } else if (classOf[AnyRef].equals(cls)) {
      new UntypedObjectDeserializer(cfg)
    } else {
      null
    }
  }

  def companion[T](cls: Class[_]): T = {
    Class.forName(cls.getName + "$").getField("MODULE$").get(null).asInstanceOf[T]
  }

  lazy val orderings = Map[Class[_], Ordering[_]](
    classOf[Boolean]    -> Ordering.Boolean,
    classOf[Byte]       -> Ordering.Byte,
    classOf[Char]       -> Ordering.Char,
    classOf[Double]     -> Ordering.Double,
    classOf[Int]        -> Ordering.Int,
    classOf[Float]      -> Ordering.Float,
    classOf[Long]       -> Ordering.Long,
    classOf[Short]      -> Ordering.Short,
    classOf[String]     -> Ordering.String,
    classOf[BigInt]     -> Ordering.BigInt,
    classOf[BigDecimal] -> Ordering.BigDecimal)

  def ordering(t: JavaType): Ordering[Any] = {
    val cls = t.getRawClass
    orderings.getOrElse(cls, {
      val orderings = for (i <- 0 until t.containedTypeCount) yield ordering(t.containedType(0))
      val params = Array.fill(orderings.length)(classOf[Ordering[_]])
      val method = Ordering.getClass.getMethod(cls.getSimpleName, params:_*)
      method.invoke(Ordering, orderings:_*)
    }).asInstanceOf[Ordering[Any]]
  }
}

class ScalaSerializers extends Serializers.Base {
  override def findSerializer(cfg: SerializationConfig, t: JavaType, bd: BeanDescription): JsonSerializer[_] = {
    val cls = t.getRawClass

    if (classOf[GenMap[_, _]].isAssignableFrom(cls)) {
      new MapSerializer(t)
    } else if (classOf[GenIterable[_]].isAssignableFrom(cls)) {
      var vT = t.containedType(0)
      if (vT == null) vT = cfg.getTypeFactory.constructType(classOf[AnyRef])
      new IterableSerializer(vT)
    } else if (classOf[Option[_]].isAssignableFrom(cls)) {
      new OptionSerializer(t)
    } else if (classOf[Product].isAssignableFrom(cls) && cls.getName.startsWith("scala.Tuple")) {
      new TupleSerializer(t)
    } else if (classOf[Product].isAssignableFrom(cls)) {
      ScalaTypeSig(cfg.getTypeFactory, t) match {
        case Some(sts) if sts.isCaseClass => new CaseClassSerializer(t, sts.annotatedAccessors)
        case _                            => null
      }
    } else if (classOf[Symbol].isAssignableFrom(cls)) {
      new SymbolSerializer(t)
    } else if (classOf[Enumeration$Val].isAssignableFrom(cls)) {
      ser.std.ToStringSerializer.instance
    } else {
      null
    }
  }
}

case class Accessor(
  name:    String,
  `type`:  JavaType,
  default: Option[Method],
  ignored: Boolean = false,
  include: Include = ALWAYS
)

class ScalaTypeSig(val tf: TypeFactory, val `type`: JavaType, val sig: ScalaSig) {
  import tools.scalap.scalax.rules.scalasig.{Method => _,  _}

  val cls = sig.topLevelClasses.head.asInstanceOf[ClassSymbol]

  def isCaseClass = cls.isCase

  lazy val constructor: Constructor[_] = {
    val types = accessors.map(_.`type`.getRawClass)
    `type`.getRawClass.getDeclaredConstructors.find { c =>
      val pairs = c.getParameterTypes.zip(types)
      pairs.length == types.length && pairs.forall {
        case (a, b) => a.isAssignableFrom(b) || (a == classOf[AnyRef] && b.isPrimitive)
      }
    }.get
  }

  lazy val accessors: List[Accessor] = {
    var index = 1
    cls.children.foldLeft(List.newBuilder[Accessor]) {
      (accessors, c) =>
        if (c.isCaseAccessor && !c.isPrivate) {
          val sym  = c.asInstanceOf[MethodSymbol]
          val name = sym.name
          val typ  = resolve(sym.infoType)
          accessors += Accessor(name, typ, default(`type`.getRawClass, "apply", index))
          index += 1
        }
        accessors
    }.result
  }

  def default(cls: Class[_], method: String, index: Int): Option[Method] = try {
    val name = "%s$default$%d".format(method, index)
    Some(cls.getDeclaredMethod(name))
  } catch {
    case e:NoSuchMethodException => None
  }

  def annotatedAccessors: Array[Accessor] = {
    classAnnotatedAccessors.zip(constructor.getParameterAnnotations).map {
      case (accessor: Accessor, annotations: Array[Annotation]) =>
        annotations.foldLeft(accessor) {
          case (accessor, a:JsonProperty) if a.value != "" => accessor.copy(name    = a.value)
          case (accessor, a:JsonIgnore)                    => accessor.copy(ignored = a.value)
          case (accessor, a:JsonInclude)                   => accessor.copy(include = a.value)
          case (accessor, _)                               => accessor
        }
    }.toArray
  }

  def classAnnotatedAccessors: List[Accessor] = {
    `type`.getRawClass.getAnnotations.foldLeft(accessors) {
      case (accessors, ignore: JsonIgnoreProperties) =>
        val ignored = ignore.value.toSet
        accessors.map(a => a.copy(ignored = ignored.contains(a.name)))
      case (accessors, include: JsonInclude) =>
        accessors.map(a => a.copy(include = include.value))
      case (accessors, _) =>
        accessors
    }
  }

  def creatorAccessors(m: Method): Array[Accessor] = {
    val cls   = m.getDeclaringClass
    var index = 0
    m.getGenericParameterTypes.zip(m.getParameterAnnotations).map {
      case (t: java.lang.reflect.Type, annotations: Array[Annotation]) =>
        val Some(a) = annotations.find(_.isInstanceOf[JsonProperty])
        val name    = a.asInstanceOf[JsonProperty].value
        index += 1
        Accessor(name, tf.constructType(t), default(cls, m.getName, index))
    }
  }

  def creator: Creator = {
    val c = Class.forName(`type`.getRawClass.getName + "$").getField("MODULE$").get(null)
    c.getClass.getDeclaredMethods.find(_.getAnnotation(classOf[JsonCreator]) != null) match {
      case Some(m) => new CompanionCreator(m, c, creatorAccessors(m))
      case None    => new ConstructorCreator(constructor, annotatedAccessors)
    }
  }

  lazy val contained = (0 until `type`.containedTypeCount).map {
    i => (`type`.containedTypeName(i) -> `type`.containedType(i))
  }.toMap

  def resolve(t: Type): JavaType = t match {
    case NullaryMethodType(t2) =>
      resolve(t2)
    case TypeRefType(_, TypeSymbol(s), Nil) =>
      contained(s.name)
    case TypeRefType(_, s, Nil) =>
      tf.constructType(ScalaTypeSig.resolve(s))
    case TypeRefType(_, s, a :: Nil) if s.path == "scala.Array" =>
      ArrayType.construct(resolve(a), null, null)
    case TypeRefType(_, s, args) =>
      val params = args.map(resolve(_))
      tf.constructParametricType(ScalaTypeSig.resolve(s), params: _ *)
  }
}

object ScalaTypeSig {
  import tools.scalap.scalax.rules.scalasig.{ScalaSigParser, Symbol}
  import scala.collection.immutable._

  def apply(tf: TypeFactory, t: JavaType): Option[ScalaTypeSig] = {
    ScalaSigParser.parse(t.getRawClass) match {
      case Some(sig) => Some(new ScalaTypeSig(tf, t, sig))
      case None      => None
    }
  }

  val types = Map[String, Class[_]](
    "scala.Boolean"           -> classOf[Boolean],
    "scala.Byte"              -> classOf[Byte],
    "scala.Char"              -> classOf[Char],
    "scala.Double"            -> classOf[Double],
    "scala.Int"               -> classOf[Int],
    "scala.Float"             -> classOf[Float],
    "scala.Long"              -> classOf[Long],
    "scala.Short"             -> classOf[Short],
    "scala.AnyRef"            -> classOf[AnyRef],
    "scala.Predef.Map"        -> classOf[Map[_, _]],
    "scala.Predef.Set"        -> classOf[Set[_]],
    "scala.Predef.String"     -> classOf[String],
    "scala.package.List"      -> classOf[List[_]],
    "scala.package.Seq"       -> classOf[Seq[_]],
    "scala.package.Vector"    -> classOf[Vector[_]],
    "scala.Enumeration.Value" -> classOf[Enumeration$Val]
  ).withDefault(Class.forName(_))

  def resolve(s: Symbol) = types(s.path)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy