Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

merge Fixes reflection for value types in generic classes and fixes v…

…alidation error serializer
  • Loading branch information...
commit 2da04ca1c602d6b6f0d995a8a0f07ea35374619b 2 parents 9a1d5cf + 5ee31b2
@casualjim casualjim authored
View
19 commands/src/test/scala/org/scalatra/validation/ValidationSerializerSpec.scala
@@ -0,0 +1,19 @@
+package org.scalatra
+package validation
+
+import org.specs2.mutable.Specification
+import org.json4s._
+
+
+class ValidationSerializerSpec extends Specification {
+
+ implicit val formats: Formats =
+ DefaultFormats + new ErrorCodeSerializer(org.scalatra.validation.NotFound) + new ValidationErrorSerializer()
+
+ "A validation error serializer" should {
+ "serialize a validation error" in {
+ val err = ValidationError("the error message", FieldName("a_field"), org.scalatra.validation.NotFound)
+ Extraction.decompose(err) must_== JObject(JField("message", JString("the error message")) :: "field" -> JString("a_field") :: "code" -> JString("NotFound") :: Nil)
+ }
+ }
+}
View
20 project/build.scala
@@ -8,7 +8,6 @@ import org.scalatra.sbt.ScalatraPlugin.scalatraWithWarOverlays
object ScalatraBuild extends Build {
import Dependencies._
- import Resolvers._
lazy val scalatraSettings = Defaults.defaultSettings ++ ls.Plugin.lsSettings ++ Seq(
organization := "org.scalatra",
@@ -19,7 +18,7 @@ object ScalatraBuild extends Build {
javacOptions ++= Seq("-target", "1.6", "-source", "1.6", "-Xlint:deprecation"),
manifestSetting,
publishSetting,
- resolvers ++= Seq(sonatypeNexusSnapshots),
+ resolvers ++= Seq(Opts.resolver.sonatypeSnapshots, Opts.resolver.sonatypeReleases),
(LsKeys.tags in LsKeys.lsync) := Seq("web", "sinatra", "scalatra", "akka"),
(LsKeys.docsUrl in LsKeys.lsync) := Some(new URL("http://www.scalatra.org/guides/"))
) ++ mavenCentralFrouFrou
@@ -108,7 +107,6 @@ object ScalatraBuild extends Build {
base = file("scalate"),
settings = scalatraSettings ++ Seq(
libraryDependencies <+= scalaVersion(scalate),
- resolvers ++= Seq(sonatypeNexusSnapshots),
description := "Scalate integration with Scalatra",
LsKeys.tags in LsKeys.lsync ++= Seq("templating", "scalate", "ssp", "jade", "mustache", "scaml", "haml")
)
@@ -233,7 +231,6 @@ object ScalatraBuild extends Build {
id = "scalatra-example",
base = file("example"),
settings = scalatraSettings ++ doNotPublish ++ scalatraWithWarOverlays ++ Seq(
- resolvers ++= Seq(sonatypeNexusSnapshots),
libraryDependencies += servletApi % "container;test",
libraryDependencies += jettyWebsocket % "container;test",
libraryDependencies ++= Seq(jettyWebapp % "container;test", slf4jSimple),
@@ -310,7 +307,7 @@ object ScalatraBuild extends Build {
private val jettyVersion = "8.1.10.v20130312"
- private val json4sVersion = "3.2.0"
+ private val json4sVersion = "3.2.1"
private val scalateArtifact: String => String = {
case sv if sv startsWith "2.8." => "scalate-core"
@@ -347,7 +344,7 @@ object ScalatraBuild extends Build {
private val specs2Version: String => String = {
case sv if sv startsWith "2.8." => "1.5"
case "2.9.0-1" => "1.8.2"
- case sv if sv startsWith "2.9." => "1.12.3"
+ case sv if sv startsWith "2.9." => "1.12.4.1"
case _ => "1.14"
}
@@ -358,13 +355,6 @@ object ScalatraBuild extends Build {
private val swaggerVersion = "1.2.0"
}
- object Resolvers {
- val sonatypeNexusSnapshots = "Sonatype Nexus Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
- val sonatypeNexusReleases = "Sonatype Nexus Releases" at "https://oss.sonatype.org/content/repositories/releases"
- val sonatypeNexusStaging = "Sonatype Nexus Staging" at "https://oss.sonatype.org/service/local/staging/deploy/maven2"
- val fuseSourceSnapshots = "FuseSource Snapshots" at "http://repo.fusesource.com/nexus/content/repositories/snapshots"
- }
-
lazy val manifestSetting = packageOptions <+= (name, version, organization) map {
(title, version, vendor) =>
Package.ManifestAttributes(
@@ -383,9 +373,9 @@ object ScalatraBuild extends Build {
lazy val publishSetting = publishTo <<= (version) { version: String =>
if (version.trim.endsWith("SNAPSHOT"))
- Some(sonatypeNexusSnapshots)
+ Some(Opts.resolver.sonatypeSnapshots)
else
- Some(sonatypeNexusStaging)
+ Some(Opts.resolver.sonatypeStaging)
}
// Things we care about primarily because Maven Central demands them
View
8 specs2/src/main/scala/org/scalatra/test/specs2/BaseScalatraSpec.scala
@@ -6,10 +6,10 @@ import org.specs2.specification.{SpecificationStructure, BaseSpecification, Step
import org.specs2.mutable.FragmentsBuilder
/**
-* A base specification structure that starts the tester before the
-* specification and stops it afterward. Clients probably want to extend
-* ScalatraSpec or MutableScalatraSpec.
-*/
+ * A base specification structure that starts the tester before the
+ * specification and stops it afterward. Clients probably want to extend
+ * ScalatraSpec or MutableScalatraSpec.
+ */
trait BaseScalatraSpec extends SpecificationStructure with FragmentsBuilder with ScalatraTests {
override def map(fs: =>Fragments) = Step(start()) ^ super.map(fs) ^ Step(stop())
}
View
3  specs2/src/main/scala/org/scalatra/test/specs2/ScalatraSpec.scala
@@ -4,7 +4,6 @@ package specs2
import org.specs2.SpecificationLike
-
/**
* A Specification that starts the tester before the specification and stops it
* afterward.
@@ -12,4 +11,4 @@ import org.specs2.SpecificationLike
* This is a spec of the immutable variation of the specs2 framework.
* All documentation for specs2 still applies.
*/
-trait ScalatraSpec extends SpecificationLike with BaseScalatraSpec
+trait ScalatraSpec extends SpecificationLike with BaseScalatraSpec
View
4 swagger/src/main/scala/org/scalatra/swagger/reflect/ManifestFactory.scala
@@ -5,7 +5,6 @@ import java.lang.reflect.{ TypeVariable, WildcardType, ParameterizedType, Type,
private[swagger] object ManifestFactory {
def manifestOf(t: Type): Manifest[_] = t match {
- case c: Class[_] => fromClass(c)
case pt: ParameterizedType =>
val clazz = manifestOf(pt.getRawType).erasure
@@ -31,6 +30,9 @@ private[swagger] object ManifestFactory {
val upper = wt.getBounds
if (upper != null && upper.size > 0) manifestOf(upper(0))
else manifestOf(classOf[AnyRef])
+
+ case c: Class[_] => fromClass(c)
+
}
def manifestOf(erasure: Class[_], typeArgs: Seq[Manifest[_]]): Manifest[_] = {
View
247 swagger/src/main/scala/org/scalatra/swagger/reflect/Reflector.scala
@@ -1,17 +1,25 @@
package org.scalatra.swagger.reflect
import java.{util => jutil}
-import java.lang.reflect.{Type, TypeVariable, ParameterizedType, Modifier}
+import java.lang.reflect._
import scala.util.control.Exception._
import collection.JavaConverters._
import java.util.Date
import java.sql.Timestamp
+import collection.mutable.ArrayBuffer
+import org.scalatra.swagger.reflect.SingletonDescriptor
+import org.scalatra.swagger.reflect.ClassDescriptor
+import scala.Some
+import org.scalatra.swagger.reflect.ConstructorParamDescriptor
+import org.scalatra.swagger.reflect.PrimitiveDescriptor
+import org.scalatra.swagger.reflect.PropertyDescriptor
+import org.scalatra.swagger.reflect.ConstructorDescriptor
object Reflector {
private[this] val rawClasses = new Memo[Type, Class[_]]
private[this] val unmangledNames = new Memo[String, String]
- private[this] val descriptors = new Memo[ScalaType, Descriptor]
+ private[this] val descriptors = new Memo[ScalaType, ObjectDescriptor]
private[this] val primitives = {
Set[Type](classOf[String], classOf[Char], classOf[Int], classOf[Long], classOf[Double],
@@ -28,140 +36,137 @@ object Reflector {
def isExcluded(t: Type, excludes: Seq[Type] = Nil) = (defaultExcluded ++ excludes) contains t
- def scalaTypeOf[T](implicit mf: Manifest[T]): ScalaType = {
- ScalaType(mf)
- }
-
- def scalaTypeOf(clazz: Class[_]): ScalaType = {
- val mf = ManifestFactory.manifestOf(clazz)
- ScalaType(mf)
- }
-
- def scalaTypeOf(t: Type): ScalaType = {
- val mf = ManifestFactory.manifestOf(t)
- ScalaType(mf)
- }
-
- def scalaTypeOf(name: String): Option[ScalaType] = Reflector.resolveClass[AnyRef](name, ClassLoaders) map (c => scalaTypeOf(c))
-
- def describe[T](implicit mf: Manifest[T]): Descriptor = describe(scalaTypeOf[T])
-
- def describe(clazz: Class[_]): Descriptor = describe(scalaTypeOf(clazz))
-
- def describe(fqn: String): Option[Descriptor] =
- Reflector.scalaTypeOf(fqn) map (describe(_: ScalaType))
-
- def describe(st: ScalaType): Descriptor = {
- if (st.isCollection || st.isOption) describe(st.typeArgs.head)
- descriptors(st, Reflector.createClassDescriptor)
- }
-
-
- def resolveClass[X <: AnyRef](c: String, classLoaders: Iterable[ClassLoader]): Option[Class[X]] = classLoaders match {
- case Nil => sys.error("resolveClass: expected 1+ classloaders but received empty list")
- case List(cl) => Some(Class.forName(c, true, cl).asInstanceOf[Class[X]])
- case many => {
- try {
- var clazz: Class[_] = null
- val iter = many.iterator
- while (clazz == null && iter.hasNext) {
- try {
- clazz = Class.forName(c, true, iter.next())
+ def scalaTypeOf[T](implicit mf: Manifest[T]): ScalaType = ScalaType(mf)
+ def scalaTypeOf(clazz: Class[_]): ScalaType = ScalaType(ManifestFactory.manifestOf(clazz))
+ def scalaTypeOf(t: Type): ScalaType = ScalaType(ManifestFactory.manifestOf(t))
+
+ private[this] val stringTypes = new Memo[String, Option[ScalaType]]
+ def scalaTypeOf(name: String): Option[ScalaType] =
+ stringTypes(name, resolveClass[AnyRef](_, ClassLoaders) map (c => scalaTypeOf(c)))
+
+ def describe[T](implicit mf: Manifest[T]): ObjectDescriptor = describe(scalaTypeOf[T])
+ def describe(clazz: Class[_]): ObjectDescriptor = describe(scalaTypeOf(clazz))
+ def describe(fqn: String): Option[ObjectDescriptor] =
+ scalaTypeOf(fqn) map (describe(_))
+ def describe(st: ScalaType, paranamer: ParameterNameReader = ParanamerReader): ObjectDescriptor =
+ descriptors(st, createDescriptor(_, paranamer))
+
+ def resolveClass[X <: AnyRef](c: String, classLoaders: Iterable[ClassLoader]): Option[Class[X]] = classLoaders match {
+ case Nil => sys.error("resolveClass: expected 1+ classloaders but received empty list")
+ case List(cl) => Some(Class.forName(c, true, cl).asInstanceOf[Class[X]])
+ case many => {
+ try {
+ var clazz: Class[_] = null
+ val iter = many.iterator
+ while (clazz == null && iter.hasNext) {
+ try {
+ clazz = Class.forName(c, true, iter.next())
+ }
+ catch {
+ case e: ClassNotFoundException => // keep going, maybe it's in the next one
+ }
}
- catch {
- case e: ClassNotFoundException => // keep going, maybe it's in the next one
- }
- }
- if (clazz != null) Some(clazz.asInstanceOf[Class[X]]) else None
- }
- catch {
- case _: Throwable => None
+ if (clazz != null) Some(clazz.asInstanceOf[Class[X]]) else None
+ }
+ catch {
+ case _: Throwable => None
+ }
}
}
- }
- private[reflect] def createClassDescriptor(tpe: ScalaType): Descriptor = {
-
- def properties: Seq[PropertyDescriptor] = {
- def fields(clazz: Class[_]): List[PropertyDescriptor] = {
- val lb = new jutil.LinkedList[PropertyDescriptor]().asScala
- val ls = clazz.getDeclaredFields.toIterator
- while (ls.hasNext) {
- val f = ls.next()
- if (!Modifier.isStatic(f.getModifiers) || !Modifier.isTransient(f.getModifiers) || !Modifier.isPrivate(f.getModifiers)) {
- val st = ScalaType(f.getType, f.getGenericType match {
- case p: ParameterizedType => p.getActualTypeArguments map (c => scalaTypeOf(c))
- case _ => Nil
- })
- val decoded = unmangleName(f.getName)
- f.setAccessible(true)
- lb += PropertyDescriptor(decoded, f.getName, st, f)
- }
+ private[reflect] def createDescriptor(tpe: ScalaType, paramNameReader: ParameterNameReader = ParanamerReader): ObjectDescriptor = {
+ if (tpe.isPrimitive) {
+ PrimitiveDescriptor(tpe.simpleName, tpe.fullName, tpe)
+ } else {
+
+ val path = if (tpe.rawFullName.endsWith("$")) tpe.rawFullName else "%s$".format(tpe.rawFullName)
+ val c = resolveClass(path, Vector(getClass.getClassLoader))
+ val companion = c flatMap { cl =>
+ allCatch opt {
+ SingletonDescriptor(cl.getSimpleName, cl.getName, scalaTypeOf(cl), cl.getField(ModuleFieldName).get(null), Seq.empty)
+ }
}
- if (clazz.getSuperclass != null)
- lb ++= fields(clazz.getSuperclass)
- lb.toList
- }
- 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)))
+ def properties: Seq[PropertyDescriptor] = {
+ def fields(clazz: Class[_]): List[PropertyDescriptor] = {
+ val lb = new ArrayBuffer[PropertyDescriptor]()
+ val ls = clazz.getDeclaredFields.toIterator
+ while (ls.hasNext) {
+ val f = ls.next()
+ if (!Modifier.isStatic(f.getModifiers) || !Modifier.isTransient(f.getModifiers) || !Modifier.isPrivate(f.getModifiers)) {
+ val st = ScalaType(f.getType, f.getGenericType match {
+ case p: ParameterizedType => p.getActualTypeArguments.toSeq.zipWithIndex map { case (cc, i) =>
+ if (cc == classOf[java.lang.Object]) Reflector.scalaTypeOf(ScalaSigReader.readField(f.getName, clazz, i))
+ else Reflector.scalaTypeOf(cc)
+ }
+ case _ => Nil
+ })
+ val decoded = unmangleName(f.getName)
+ f.setAccessible(true)
+ lb += PropertyDescriptor(decoded, f.getName, st, f)
+ }
+ }
+ if (clazz.getSuperclass != null) lb ++= fields(clazz.getSuperclass)
+ lb.toList
}
- 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
- }
- }
+ fields(tpe.erasure)
+ }
- 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 {
- case (paramName, index) =>
- val decoded = unmangleName(paramName)
- val default = companion flatMap {
- comp =>
- defaultValue(comp.erasure.erasure, comp.instance, index)
+ 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)))
}
- val theType = ctorParamType(paramName, index, tpe, ctorParameterNames.toList, genParams(index))
- ConstructorParamDescriptor(decoded, paramName, index, theType, default)
+ st.copy(typeArgs = actualArgs)
+ case v: WildcardType =>
+ val upper = v.getUpperBounds
+ if (upper != null && upper.size > 0) scalaTypeOf(upper(0))
+ else scalaTypeOf[AnyRef]
+ 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
}
- ConstructorDescriptor(ctorParams.toSeq, ctor, isPrimary = false)
- }
- }
+ }
- if (tpe.isPrimitive) PrimitiveDescriptor(tpe.simpleName, tpe.fullName, tpe)
- else {
- val path = if (tpe.rawFullName.endsWith("$")) tpe.rawFullName else "%s$".format(tpe.rawFullName)
- val c = resolveClass(path, Vector(getClass.getClassLoader))
- val companion = c flatMap { cl =>
- allCatch opt {
- SingletonDescriptor(cl.getSimpleName, cl.getName, scalaTypeOf(cl), cl.getField(ModuleFieldName).get(null), Seq.empty)
+ def constructors: Seq[ConstructorDescriptor] = {
+ tpe.erasure.getConstructors.toSeq map {
+ ctor =>
+ val ctorParameterNames = if (Modifier.isPublic(ctor.getModifiers) && ctor.getParameterTypes.length > 0)
+ allCatch opt { paramNameReader.lookupParameterNames(ctor) } getOrElse Nil
+ else
+ Nil
+ val genParams = Vector(ctor.getGenericParameterTypes: _*)
+ val ctorParams = ctorParameterNames.zipWithIndex map {
+ case (paramName, index) =>
+ val decoded = unmangleName(paramName)
+ val default = companion flatMap {
+ comp =>
+ defaultValue(comp.erasure.erasure, comp.instance, index)
+ }
+ val theType = ctorParamType(paramName, index, tpe, ctorParameterNames.toList, genParams(index))
+ ConstructorParamDescriptor(decoded, paramName, index, theType, default)
+ }
+ ConstructorDescriptor(ctorParams.toSeq, ctor, isPrimary = false)
+ }
}
+
+ ClassDescriptor(tpe.simpleName, tpe.fullName, tpe, companion, constructors, properties)
}
- ClassDescriptor(tpe.simpleName, tpe.fullName, tpe, companion, constructors(companion), properties)
}
- }
def defaultValue(compClass: Class[_], compObj: AnyRef, argIndex: Int) = {
allCatch.withApply(_ => None) {
View
155 swagger/src/main/scala/org/scalatra/swagger/reflect/ScalaSigReader.scala
@@ -4,18 +4,65 @@ import tools.scalap.scalax.rules.scalasig._
import annotation.tailrec
private[reflect] object ScalaSigReader {
+ def readConstructor(argName: String, clazz: Class[_], typeArgIndex: Int, argNames: List[String]): Class[_] = {
+ val cl = findClass(clazz)
+ val cstr = findConstructor(cl, argNames).getOrElse(fail("Can't find constructor for " + clazz))
+ findArgType(cstr, argNames.indexOf(argName), typeArgIndex)
+ }
+ def readConstructor(argName: String, clazz: Class[_], typeArgIndexes: List[Int], argNames: List[String]): Class[_] = {
+ val cl = findClass(clazz)
+ val cstr = findConstructor(cl, argNames).getOrElse(fail("Can't find constructor for " + clazz))
+ findArgType(cstr, argNames.indexOf(argName), typeArgIndexes)
+ }
+
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))
+ val cstr = findConstructor(cl, argNames).getOrElse(fail("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))
+ val cstr = findConstructor(cl, argNames).getOrElse(fail("Can't find constructor for " + clazz))
findArgType(cstr, argNames.indexOf(argName), typeArgIndexes)
}
+ def readField(name: String, clazz: Class[_], typeArgIndex: Int): Class[_] = {
+ def read(current: Class[_]): MethodSymbol = {
+ if (current == null)
+ fail("Can't find field " + name + " from " + clazz)
+ else
+ findField(findClass(current), name).getOrElse(read(current.getSuperclass))
+ }
+ findArgTypeForField(read(clazz), typeArgIndex)
+ }
+
+ def findClass(clazz: Class[_]): ClassSymbol = {
+ val sig = findScalaSig(clazz).getOrElse(fail("Can't find ScalaSig for " + clazz))
+ findClass(sig, clazz).getOrElse(fail("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 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)
+ }
+
+ private def findField(c: ClassSymbol, name: String): Option[MethodSymbol] =
+ (c.children collect { case m: MethodSymbol if m.name == name => m }).headOption
+
def findArgType(s: MethodSymbol, argIdx: Int, typeArgIndex: Int): Class[_] = {
def findPrimitive(t: Type): Symbol = {
t match {
@@ -28,25 +75,14 @@ private[reflect] object ScalaSigReader {
val ta = args(typeArgIndex)
ta match {
case ref @ TypeRefType(_, _, _) => findPrimitive(ref)
- case x => sys.error("Unexpected type info " + x)
+ case x => fail("Unexpected type info " + x)
}
- case x => sys.error("Unexpected type info " + x)
+ case x => fail("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
@@ -59,37 +95,40 @@ private[reflect] object ScalaSigReader {
val ta = args(typeArgIndexes(ii))
ta match {
case ref @ TypeRefType(_, _, _) => findPrimitive(ref, curr + 1)
- case x => sys.error("Unexpected type info " + x)
+ case x => fail("Unexpected type info " + x)
}
- case x => sys.error("Unexpected type info " + x)
+ case x => fail("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
+ private def findArgTypeForField(s: MethodSymbol, typeArgIdx: Int): Class[_] = {
+ val t = s.infoType match {
+ case NullaryMethodType(TypeRefType(_, _, args)) => args(typeArgIdx)
}
- 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 findPrimitive(t: Type): Symbol = t match {
+ case TypeRefType(ThisType(_), symbol, _) => symbol
+ case ref @ TypeRefType(_, _, _) => findPrimitive(ref)
+ case x => fail("Unexpected type info " + x)
+ }
+ toClass(findPrimitive(t))
}
- 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
- }
- }
+ private 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 findScalaSig(clazz: Class[_]): Option[ScalaSig] =
parseClassFileFromByteCode(clazz).orElse(findScalaSig(clazz.getDeclaringClass))
@@ -100,4 +139,52 @@ private[reflect] object ScalaSigReader {
} catch {
case e: NullPointerException => None // yes, this is the exception, but it is totally unhelpful to the end user
}
+
+// def typeRefType(ms: MethodSymbol): TypeRefType = ms.infoType match {
+// case PolyType(tr @ TypeRefType(_, _, _), _) => tr
+// case NullaryMethodType(tr @ TypeRefType(_, _, _)) => tr
+// case NullaryMethodType(ExistentialType(tr @ TypeRefType(_, _, _), _)) => tr
+// }
+
+ val ModuleFieldName = "MODULE$"
+ val ClassLoaders = Vector(this.getClass.getClassLoader)
+
+ def companionClass(clazz: Class[_], classLoaders: Iterable[ClassLoader]) = {
+ val path = if (clazz.getName.endsWith("$")) clazz.getName else "%s$".format(clazz.getName)
+ val c = resolveClass(path, classLoaders)
+ if (c.isDefined) c.get else sys.error("Could not resolve clazz='%s'".format(path))
+ }
+
+ def companionObject(clazz: Class[_], classLoaders: Iterable[ClassLoader]) =
+ companionClass(clazz, classLoaders).getField(ModuleFieldName).get(null)
+
+ def companions(t: java.lang.reflect.Type) = {
+ val k = Reflector.rawClassOf(t)
+ val cc = companionClass(k, ClassLoaders)
+ (cc, cc.getField(ModuleFieldName).get(null))
+ }
+
+ def resolveClass[X <: AnyRef](c: String, classLoaders: Iterable[ClassLoader]): Option[Class[X]] = classLoaders match {
+ case Nil => sys.error("resolveClass: expected 1+ classloaders but received empty list")
+ case List(cl) => Some(Class.forName(c, true, cl).asInstanceOf[Class[X]])
+ case many => {
+ try {
+ var clazz: Class[_] = null
+ val iter = many.iterator
+ while (clazz == null && iter.hasNext) {
+ try {
+ clazz = Class.forName(c, true, iter.next())
+ }
+ catch {
+ case e: ClassNotFoundException => // keep going, maybe it's in the next one
+ }
+ }
+
+ if (clazz != null) Some(clazz.asInstanceOf[Class[X]]) else None
+ }
+ catch {
+ case _: Throwable => None
+ }
+ }
+ }
}
View
135 swagger/src/main/scala/org/scalatra/swagger/reflect/descriptors.scala
@@ -4,29 +4,115 @@ import java.lang.reflect.{Field, TypeVariable}
sealed trait Descriptor
object ScalaType {
- def apply[T](mf: Manifest[T]): ScalaType = new ScalaType(mf)
+ private val types = new Memo[Manifest[_], ScalaType]
+
+ def apply[T](mf: Manifest[T]): ScalaType = {
+ /* optimization */
+ if (mf.erasure == classOf[Int] || mf.erasure == classOf[java.lang.Integer]) ScalaType.IntType
+ else if (mf.erasure == classOf[Long] || mf.erasure == classOf[java.lang.Long]) ScalaType.LongType
+ else if (mf.erasure == classOf[Byte] || mf.erasure == classOf[java.lang.Byte]) ScalaType.ByteType
+ else if (mf.erasure == classOf[Short] || mf.erasure == classOf[java.lang.Short]) ScalaType.ShortType
+ else if (mf.erasure == classOf[Float] || mf.erasure == classOf[java.lang.Float]) ScalaType.FloatType
+ else if (mf.erasure == classOf[Double] || mf.erasure == classOf[java.lang.Double]) ScalaType.DoubleType
+ else if (mf.erasure == classOf[BigInt] || mf.erasure == classOf[java.math.BigInteger]) ScalaType.BigIntType
+ else if (mf.erasure == classOf[BigDecimal] || mf.erasure == classOf[java.math.BigDecimal]) ScalaType.BigDecimalType
+ else if (mf.erasure == classOf[Boolean] || mf.erasure == classOf[java.lang.Boolean]) ScalaType.BooleanType
+ else if (mf.erasure == classOf[String] || mf.erasure == classOf[java.lang.String]) ScalaType.StringType
+ else if (mf.erasure == classOf[java.util.Date]) ScalaType.DateType
+ else if (mf.erasure == classOf[java.sql.Timestamp]) ScalaType.TimestampType
+ else if (mf.erasure == classOf[Symbol]) ScalaType.SymbolType
+ else if (mf.erasure == classOf[Number]) ScalaType.NumberType
+ /* end optimization */
+ else {
+ if (mf.typeArguments.isEmpty) types(mf, new ScalaType(_))
+ else new ScalaType(mf)
+// if (!mf.erasure.isArray) types(mf, new ScalaType(_))
+// else {
+// val nmf = ManifestFactory.manifestOf(mf.erasure, List(ManifestFactory.manifestOf(mf.erasure.getComponentType)))
+// types(nmf, new ScalaType(_))
+// }
+// new ScalaType(mf)
+ }
+ }
def apply(erasure: Class[_], typeArgs: Seq[ScalaType] = Seq.empty): ScalaType = {
val mf = ManifestFactory.manifestOf(erasure, typeArgs.map(_.manifest))
- new ScalaType(mf)
+ ScalaType(mf)
+ }
+
+ private val IntType: ScalaType = new PrimitiveScalaType(Manifest.Int)
+ private val NumberType: ScalaType = new PrimitiveScalaType(manifest[Number])
+ private val LongType: ScalaType = new PrimitiveScalaType(Manifest.Long)
+ private val ByteType: ScalaType = new PrimitiveScalaType(Manifest.Byte)
+ private val ShortType: ScalaType = new PrimitiveScalaType(Manifest.Short)
+ private val BooleanType: ScalaType = new PrimitiveScalaType(Manifest.Boolean)
+ private val FloatType: ScalaType = new PrimitiveScalaType(Manifest.Float)
+ private val DoubleType: ScalaType = new PrimitiveScalaType(Manifest.Double)
+ private val StringType: ScalaType = new PrimitiveScalaType(manifest[java.lang.String])
+ private val SymbolType: ScalaType = new PrimitiveScalaType(manifest[Symbol])
+ private val BigDecimalType: ScalaType = new PrimitiveScalaType(manifest[BigDecimal])
+ private val BigIntType: ScalaType = new PrimitiveScalaType(manifest[BigInt])
+ private val DateType: ScalaType = new PrimitiveScalaType(manifest[java.util.Date])
+ private val TimestampType: ScalaType = new PrimitiveScalaType(manifest[java.sql.Timestamp])
+
+ private class PrimitiveScalaType(mf: Manifest[_]) extends ScalaType(mf) {
+ override val isPrimitive = true
+ }
+ private class CopiedScalaType(
+ mf: Manifest[_],
+ private[this] var _typeVars: Map[TypeVariable[_], ScalaType],
+ override val isPrimitive: Boolean) extends ScalaType(mf) {
+ override def typeVars: Map[TypeVariable[_], ScalaType] = {
+ if (_typeVars == null)
+ _typeVars = Map.empty ++
+ erasure.getTypeParameters.map(_.asInstanceOf[TypeVariable[_]]).toList.zip(manifest.typeArguments map (ScalaType(_)))
+ _typeVars
+ }
}
}
-class ScalaType(private val manifest: Manifest[_]) extends Descriptor with Equals {
+class ScalaType(private val manifest: Manifest[_]) extends Equals {
+ import ScalaType.{ types, CopiedScalaType }
+ private[this] val self = this
val erasure: Class[_] = manifest.erasure
+// private[this] var _typeArgs: Seq[ScalaType] = null
+// def typeArgs: Seq[ScalaType] = {
+// if (_typeArgs == null)
+// _typeArgs = manifest.typeArguments.map(ta => Reflector.scalaTypeOf(ta)) ++ (
+// if (erasure.isArray) List(Reflector.scalaTypeOf(erasure.getComponentType)) else Nil
+// )
+// _typeArgs
+// }
+
val typeArgs: Seq[ScalaType] = manifest.typeArguments.map(ta => Reflector.scalaTypeOf(ta)) ++ (
if (erasure.isArray) List(Reflector.scalaTypeOf(erasure.getComponentType)) else Nil
)
- val typeVars: Map[TypeVariable[_], ScalaType] = Map.empty ++
- erasure.getTypeParameters.map(_.asInstanceOf[TypeVariable[_]]).toList.zip(manifest.typeArguments map (ScalaType(_)))
+ private[this] var _typeVars: Map[TypeVariable[_], ScalaType] = null
+ def typeVars: Map[TypeVariable[_], ScalaType] = {
+ if (_typeVars == null)
+ _typeVars = Map.empty ++
+ erasure.getTypeParameters.map(_.asInstanceOf[TypeVariable[_]]).toList.zip(manifest.typeArguments map (ScalaType(_)))
+ _typeVars
+ }
+
val isArray: Boolean = erasure.isArray
- lazy val rawFullName: String = erasure.getName
+ private[this] var _rawFullName: String = null
+ def rawFullName: String = {
+ if (_rawFullName == null)
+ _rawFullName = erasure.getName
+ _rawFullName
+ }
- lazy val rawSimpleName: String = erasure.getSimpleName
+ private[this] var _rawSimpleName: String = null
+ def rawSimpleName: String = {
+ if (_rawSimpleName == null)
+ _rawSimpleName = erasure.getSimpleName
+ _rawSimpleName
+ }
lazy val simpleName: String =
rawSimpleName + (if (typeArgs.nonEmpty) typeArgs.map(_.simpleName).mkString("[", ", ", "]") else (if (typeVars.nonEmpty) typeVars.map(_._2.simpleName).mkString("[", ", ", "]") else ""))
@@ -34,10 +120,10 @@ class ScalaType(private val manifest: Manifest[_]) extends Descriptor with Equal
lazy val fullName: String =
rawFullName + (if (typeArgs.nonEmpty) typeArgs.map(_.fullName).mkString("[", ", ", "]") else "")
- lazy val isPrimitive: Boolean = Reflector.isPrimitive(erasure)
+ val isPrimitive = false
def isMap = classOf[Map[_, _]].isAssignableFrom(erasure)
- def isCollection = classOf[Iterable[_]].isAssignableFrom(erasure)
+ def isCollection = erasure.isArray || classOf[Iterable[_]].isAssignableFrom(erasure)
def isOption = classOf[Option[_]].isAssignableFrom(erasure)
def <:<(that: ScalaType): Boolean = manifest <:< that.manifest
def >:>(that: ScalaType): Boolean = manifest >:> that.manifest
@@ -54,8 +140,29 @@ class ScalaType(private val manifest: Manifest[_]) extends Descriptor with Equal
case _ => false
}
- def copy(typeArgs: Seq[ScalaType] = typeArgs, typeVars: Map[TypeVariable[_], ScalaType] = typeVars) = {
- new ScalaType(ManifestFactory.manifestOf(erasure, typeArgs.map(_.manifest)))
+ def copy(erasure: Class[_] = erasure, typeArgs: Seq[ScalaType] = typeArgs, typeVars: Map[TypeVariable[_], ScalaType] = _typeVars): ScalaType = {
+ /* optimization */
+ if (erasure == classOf[Int] || erasure == classOf[java.lang.Integer]) ScalaType.IntType
+ else if (erasure == classOf[Long] || erasure == classOf[java.lang.Long]) ScalaType.LongType
+ else if (erasure == classOf[Byte] || erasure == classOf[java.lang.Byte]) ScalaType.ByteType
+ else if (erasure == classOf[Short] || erasure == classOf[java.lang.Short]) ScalaType.ShortType
+ else if (erasure == classOf[Float] || erasure == classOf[java.lang.Float]) ScalaType.FloatType
+ else if (erasure == classOf[Double] || erasure == classOf[java.lang.Double]) ScalaType.DoubleType
+ else if (erasure == classOf[BigInt] || erasure == classOf[java.math.BigInteger]) ScalaType.BigIntType
+ else if (erasure == classOf[BigDecimal] || erasure == classOf[java.math.BigDecimal]) ScalaType.BigDecimalType
+ else if (erasure == classOf[Boolean] || erasure == classOf[java.lang.Boolean]) ScalaType.BooleanType
+ else if (erasure == classOf[String] || erasure == classOf[java.lang.String]) ScalaType.StringType
+ else if (erasure == classOf[java.util.Date]) ScalaType.DateType
+ else if (erasure == classOf[java.sql.Timestamp]) ScalaType.TimestampType
+ else if (erasure == classOf[Symbol]) ScalaType.SymbolType
+ else if (erasure == classOf[Number]) ScalaType.NumberType
+ /* end optimization */
+ else {
+ val mf = ManifestFactory.manifestOf(erasure, typeArgs.map(_.manifest))
+ val st = new CopiedScalaType(mf, typeVars, isPrimitive)
+ if (typeArgs.isEmpty) types.replace(mf, st)
+ else st
+ }
}
override def toString: String = simpleName
@@ -75,12 +182,14 @@ case class ConstructorParamDescriptor(name: String, mangledName: String, argInde
}
case class ConstructorDescriptor(params: Seq[ConstructorParamDescriptor], constructor: java.lang.reflect.Constructor[_], isPrimary: Boolean) extends Descriptor
case class SingletonDescriptor(simpleName: String, fullName: String, erasure: ScalaType, instance: AnyRef, properties: Seq[PropertyDescriptor]) extends Descriptor
-case class ClassDescriptor(simpleName: String, fullName: String, erasure: ScalaType, companion: Option[SingletonDescriptor], constructors: Seq[ConstructorDescriptor], properties: Seq[PropertyDescriptor]) extends Descriptor {
+
+trait ObjectDescriptor extends Descriptor
+case class ClassDescriptor(simpleName: String, fullName: String, erasure: ScalaType, companion: Option[SingletonDescriptor], constructors: Seq[ConstructorDescriptor], properties: Seq[PropertyDescriptor]) extends ObjectDescriptor {
// def bestConstructor(argNames: Seq[String]): Option[ConstructorDescriptor] = {
// constructors.sortBy(-_.params.size)
// }
lazy val mostComprehensive: Seq[ConstructorParamDescriptor] = if (constructors.isEmpty) Seq.empty else constructors.sortBy(-_.params.size).head.params
}
-case class PrimitiveDescriptor(simpleName: String, fullName: String, erasure: ScalaType) extends Descriptor {
+case class PrimitiveDescriptor(simpleName: String, fullName: String, erasure: ScalaType) extends ObjectDescriptor {
}
View
18 swagger/src/main/scala/org/scalatra/swagger/reflect/package.scala
@@ -8,12 +8,24 @@ import collection.JavaConverters._
package object reflect {
private[reflect] class Memo[A, R] {
- private[this] val cache = new ConcurrentHashMap[A, R]().asScala
- def apply(x: A, f: A => R): R = cache.getOrElseUpdate(x, f(x))
+ private[this] val cache = new ConcurrentHashMap[A, R](1500, 1, 1)
+ def apply(x: A, f: A => R): R = {
+ if (cache.containsKey(x))
+ cache.get(x)
+ else {
+ val v = f(x)
+ replace(x, v)
+ }
+ }
+
+ def replace(x: A, v: R):R = {
+ cache.put(x, v)
+ v
+ }
}
trait ParameterNameReader {
- def lookupParameterNames(constructor: JConstructor[_]): Traversable[String]
+ def lookupParameterNames(constructor: JConstructor[_]): Seq[String]
}
private[reflect] val ConstructorDefault = "init$default"
private[reflect] val ModuleFieldName = "MODULE$"
Please sign in to comment.
Something went wrong with that request. Please try again.