Permalink
Browse files

Fixes reflection for value types in generic classes and fixes validat…

…ion error serializer
  • Loading branch information...
1 parent 207e8fd commit 5ee31b21627e0ea0a4f1f45ac41ae27c9d521b12 @casualjim casualjim committed Mar 22, 2013
@@ -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
@@ -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",
@@ -18,7 +17,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
@@ -106,7 +105,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")
)
@@ -231,7 +229,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),
@@ -308,7 +305,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"
@@ -356,12 +353,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"
- }
-
lazy val manifestSetting = packageOptions <+= (name, version, organization) map {
(title, version, vendor) =>
Package.ManifestAttributes(
@@ -380,9 +371,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
@@ -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[_] = {
@@ -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) {
Oops, something went wrong.

0 comments on commit 5ee31b2

Please sign in to comment.