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.cfg.MapperConfig
import com.fasterxml.jackson.databind.deser._
import com.fasterxml.jackson.databind.ser._
import com.fasterxml.jackson.databind.`type`._
import com.fasterxml.jackson.databind.introspect._

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, 3, 3, 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(cfg))
        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(cfg))
        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],
  external: String,
  ignored:  Boolean = false,
  required: Boolean = false,
  include:  Include = ALWAYS
)

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

  val cls = {
    val name = `type`.getRawClass.getCanonicalName.replace('$', '.')
    sig.symbols.collectFirst {
      case c:ClassSymbol if c.path == name => c
    }.get
  }

  def isCaseClass = cls.isCase

  def constructor(cfg: MapperConfig[_]): Constructor[_] = {
    val types = accessors(cfg).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
  }

  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 external(cfg: MapperConfig[_], name: String) = {
    val strategy = cfg.getPropertyNamingStrategy
    var external = name
    if (strategy != null) {
      external = strategy.nameForConstructorParameter(cfg, null, name)
    }
    external
  }

  def accessors(cfg: MapperConfig[_]): 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)
          val dflt = default(`type`.getRawClass, "apply", index)
          accessors += Accessor(name, typ, dflt, external(cfg, name))
          index += 1
        }
        accessors
    }.result
  }

  def annotatedAccessors(cfg: MapperConfig[_]): Array[Accessor] = {
    def property(acc: Accessor, a: JsonProperty): Accessor = {
      val name = if (a.value != "") a.value else acc.name
      acc.copy(name = name, required = a.required, external = name)
    }

    classAnnotatedAccessors(cfg).zip(constructor(cfg).getParameterAnnotations).map {
      case (accessor: Accessor, annotations: Array[Annotation]) =>
        annotations.foldLeft(accessor) {
          case (acc, a:JsonProperty) => property(acc, a)
          case (acc, a:JsonIgnore)   => acc.copy(ignored = a.value)
          case (acc, a:JsonInclude)  => acc.copy(include = a.value)
          case (acc, _)              => acc
        }
    }.toArray
  }

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

  def creatorAccessors(cfg: MapperConfig[_], 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]) =>
        index += 1
        val Some(a) = annotations.find(_.isInstanceOf[JsonProperty])
        val name    = a.asInstanceOf[JsonProperty].value
        val dflt    = default(cls, m.getName, index)
        Accessor(name, tf.constructType(t), dflt, external(cfg, name))
    }
  }

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

  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(_))
      val actual = ScalaTypeSig.resolve(s)
      tf.constructParametrizedType(actual, actual, params: _ *)
  }
}

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

  def apply(tf: TypeFactory, t: JavaType): Option[ScalaTypeSig] = {
    def findSig(cls: Class[_]): Option[ScalaSig] = {
      ScalaSigParser.parse(cls) orElse {
        val enc = cls.getEnclosingClass
        if (enc != null) findSig(enc) else None
      }
    }

    findSig(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.Any"               -> classOf[Any],
    "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(findClass(_))

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

  def findClass(name: String): Class[_] = {
    val cl = Thread.currentThread().getContextClassLoader()
    Class.forName(name, true, cl)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy