Permalink
Browse files

Merge branch '2.2.x_2.9' into 2.2.x_2.10

  • Loading branch information...
2 parents 4718822 + 5e645fa commit f80b54f9ab6bd0e370e7fa7899d8ba141425302e @casualjim casualjim committed Mar 9, 2013
@@ -6,13 +6,11 @@ import scala.util.control.Exception._
import collection.JavaConverters._
import java.util.Date
import java.sql.Timestamp
-import org.json4s.ScalaSigReader
object Reflector {
private[this] val rawClasses = new Memo[Type, Class[_]]
private[this] val unmangledNames = new Memo[String, String]
- private[this] val types = new Memo[Type, ScalaType]
private[this] val descriptors = new Memo[ScalaType, Descriptor]
private[this] val primitives = {
@@ -32,18 +30,15 @@ object Reflector {
def scalaTypeOf[T](implicit mf: Manifest[T]): ScalaType = {
ScalaType(mf)
-// types(mf.erasure, _ => ScalaType(mf))
}
def scalaTypeOf(clazz: Class[_]): ScalaType = {
val mf = ManifestFactory.manifestOf(clazz)
-// types(mf.erasure, _ => ScalaType(mf))
ScalaType(mf)
}
def scalaTypeOf(t: Type): ScalaType = {
val mf = ManifestFactory.manifestOf(t)
-// types(mf.erasure, _ => ScalaType(mf))
ScalaType(mf)
}
@@ -111,36 +106,45 @@ object Reflector {
fields(tpe.erasure)
}
+ def ctorParamType(name: String, index: Int, owner: ScalaType, ctorParameterNames: List[String], t: Type, container: Option[(ScalaType, List[Int])] = None): ScalaType = {
+ val idxes = container.map(_._2.reverse)
+ t match {
+ case v: TypeVariable[_] =>
+ val a = owner.typeVars.getOrElse(v, scalaTypeOf(v))
+ if (a.erasure == classOf[java.lang.Object]) {
+ val r = ScalaSigReader.readConstructor(name, owner, index, ctorParameterNames)
+ scalaTypeOf(r)
+ } else a
+ case v: ParameterizedType =>
+ val st = scalaTypeOf(v)
+ val actualArgs = v.getActualTypeArguments.toList.zipWithIndex map {
+ case (ct, idx) =>
+ val prev = container.map(_._2).getOrElse(Nil)
+ ctorParamType(name, index, owner, ctorParameterNames, ct, Some((st, idx :: prev)))
+ }
+ st.copy(typeArgs = actualArgs)
+ case x =>
+ val st = scalaTypeOf(x)
+ if (st.erasure == classOf[java.lang.Object])
+ scalaTypeOf(ScalaSigReader.readConstructor(name, owner, idxes getOrElse List(index), ctorParameterNames))
+ else st
+ }
+ }
+
def constructors(companion: Option[SingletonDescriptor]): Seq[ConstructorDescriptor] = {
tpe.erasure.getConstructors.toSeq map {
ctor =>
val ctorParameterNames = ParanamerReader.lookupParameterNames(ctor)
val genParams = Vector(ctor.getGenericParameterTypes: _*)
val ctorParams = ctorParameterNames.zipWithIndex map {
- cp =>
- val decoded = unmangleName(cp._1)
+ case (paramName, index) =>
+ val decoded = unmangleName(paramName)
val default = companion flatMap {
comp =>
- defaultValue(comp.erasure.erasure, comp.instance, cp._2)
+ defaultValue(comp.erasure.erasure, comp.instance, index)
}
- val theType = genParams(cp._2) match {
- case v: TypeVariable[_] =>
- val a = tpe.typeVars.getOrElse(v, scalaTypeOf(v))
- val tt = if (a.erasure == classOf[java.lang.Object])
- scalaTypeOf(ScalaSigReader.readConstructor(cp._1, tpe.erasure, cp._2, ctorParameterNames.toList))
- else a
- tt
- case x =>
- val st = scalaTypeOf(x)
- val tt = if (st.isCollection || st.isOption) {
- val inner = st.typeArgs.head
- if (inner.erasure == classOf[java.lang.Object])
- st.copy(typeArgs = Seq(scalaTypeOf(ScalaSigReader.readConstructor(cp._1, tpe.erasure, cp._2, ctorParameterNames.toList))) )
- else st
- } else st
- tt
- }
- ConstructorParamDescriptor(decoded, cp._1, cp._2, theType, default)
+ val theType = ctorParamType(paramName, index, tpe, ctorParameterNames.toList, genParams(index))
+ ConstructorParamDescriptor(decoded, paramName, index, theType, default)
}
ConstructorDescriptor(ctorParams.toSeq, ctor, isPrimary = false)
}
@@ -169,8 +173,7 @@ object Reflector {
def rawClassOf(t: Type): Class[_] = rawClasses(t, _ match {
case c: Class[_] => c
- case p: ParameterizedType =>
- rawClassOf(p.getRawType)
+ case p: ParameterizedType => rawClassOf(p.getRawType)
case x => sys.error("Raw type of " + x + " not known")
})
@@ -0,0 +1,103 @@
+package org.scalatra.swagger.reflect
+
+import tools.scalap.scalax.rules.scalasig._
+import annotation.tailrec
+
+private[reflect] object ScalaSigReader {
+ def readConstructor(argName: String, clazz: ScalaType, typeArgIndex: Int, argNames: List[String]): Class[_] = {
+ val cl = findClass(clazz.erasure)
+ val cstr = findConstructor(cl, argNames).getOrElse(sys.error("Can't find constructor for " + clazz))
+ findArgType(cstr, argNames.indexOf(argName), typeArgIndex)
+ }
+
+ def readConstructor(argName: String, clazz: ScalaType, typeArgIndexes: List[Int], argNames: List[String]): Class[_] = {
+ val cl = findClass(clazz.erasure)
+ val cstr = findConstructor(cl, argNames).getOrElse(sys.error("Can't find constructor for " + clazz))
+ findArgType(cstr, argNames.indexOf(argName), typeArgIndexes)
+ }
+
+ def findArgType(s: MethodSymbol, argIdx: Int, typeArgIndex: Int): Class[_] = {
+ def findPrimitive(t: Type): Symbol = {
+ t match {
+ case TypeRefType(ThisType(_), symbol, _) if isPrimitive(symbol) => symbol
+ case TypeRefType(_, _, TypeRefType(ThisType(_), symbol, _) :: xs) => symbol
+ case TypeRefType(_, symbol, Nil) => symbol
+ case TypeRefType(_, _, args) if typeArgIndex >= args.length =>
+ findPrimitive(args(0))
+ case TypeRefType(_, _, args) =>
+ val ta = args(typeArgIndex)
+ ta match {
+ case ref @ TypeRefType(_, _, _) => findPrimitive(ref)
+ case x => sys.error("Unexpected type info " + x)
+ }
+ case x => sys.error("Unexpected type info " + x)
+ }
+ }
+ toClass(findPrimitive(s.children(argIdx).asInstanceOf[SymbolInfoSymbol].infoType))
+ }
+
+ private[this] def toClass(s: Symbol) = s.path match {
+ case "scala.Short" => classOf[Short]
+ case "scala.Int" => classOf[Int]
+ case "scala.Long" => classOf[Long]
+ case "scala.Boolean" => classOf[Boolean]
+ case "scala.Float" => classOf[Float]
+ case "scala.Double" => classOf[Double]
+ case "scala.Byte" => classOf[Byte]
+ case _ => classOf[AnyRef]
+ }
+ private[this] def isPrimitive(s: Symbol) = toClass(s) != classOf[AnyRef]
+ def findArgType(s: MethodSymbol, argIdx: Int, typeArgIndexes: List[Int]): Class[_] = {
+ @tailrec def findPrimitive(t: Type, curr: Int): Symbol = {
+ val ii = (typeArgIndexes.length - 1) min curr
+ t match {
+ case TypeRefType(ThisType(_), symbol, _) if isPrimitive(symbol) => symbol
+ case TypeRefType(_, symbol, Nil) => symbol
+ case TypeRefType(_, _, args) if typeArgIndexes(ii) >= args.length =>
+ findPrimitive(args(0 max args.length - 1), curr + 1)
+ case TypeRefType(_, _, args) =>
+ val ta = args(typeArgIndexes(ii))
+ ta match {
+ case ref @ TypeRefType(_, _, _) => findPrimitive(ref, curr + 1)
+ case x => sys.error("Unexpected type info " + x)
+ }
+ case x => sys.error("Unexpected type info " + x)
+ }
+ }
+ toClass(findPrimitive(s.children(argIdx).asInstanceOf[SymbolInfoSymbol].infoType, 0))
+ }
+
+ def findConstructor(c: ClassSymbol, argNames: List[String]): Option[MethodSymbol] = {
+ val ms = c.children collect {
+ case m: MethodSymbol if m.name == "<init>" => m
+ }
+ ms.find(m => m.children.map(_.name) == argNames)
+ }
+
+ def findClass(clazz: Class[_]): ClassSymbol = {
+ val sig = findScalaSig(clazz).getOrElse(sys.error("Can't find ScalaSig for " + clazz))
+ findClass(sig, clazz).getOrElse(sys.error("Can't find " + clazz + " from parsed ScalaSig"))
+ }
+
+ def findClass(sig: ScalaSig, clazz: Class[_]): Option[ClassSymbol] = {
+ sig.symbols.collect { case c: ClassSymbol if !c.isModule => c }.find(_.name == clazz.getSimpleName).orElse {
+ sig.topLevelClasses.find(_.symbolInfo.name == clazz.getSimpleName).orElse {
+ sig.topLevelObjects.map { obj =>
+ val t = obj.infoType.asInstanceOf[TypeRefType]
+ t.symbol.children collect { case c: ClassSymbol => c } find(_.symbolInfo.name == clazz.getSimpleName)
+ }.head
+ }
+ }
+ }
+
+ def findScalaSig(clazz: Class[_]): Option[ScalaSig] =
+ parseClassFileFromByteCode(clazz).orElse(findScalaSig(clazz.getDeclaringClass))
+
+ private[this] def parseClassFileFromByteCode(clazz: Class[_]): Option[ScalaSig] = try {
+ // taken from ScalaSigParser parse method with the explicit purpose of walking away from NPE
+ val byteCode = ByteCode.forClass(clazz)
+ Option(ClassFileParser.parse(byteCode)) flatMap ScalaSigParser.parse
+ } catch {
+ case e: NullPointerException => None // yes, this is the exception, but it is totally unhelpful to the end user
+ }
+}

0 comments on commit f80b54f

Please sign in to comment.