Permalink
Browse files

SI-7008 @throws annotations are now populated in reflect

Runtime reflection in JavaMirrors previously forgot to fill in
@throws when importing Java reflection artifacts. Now this is fixed.

Note that generic exception types used in `throws` specifications will
be garbled (i.e. erased), because we don't use `getGenericExceptionTypes`
in favor of just `getExceptionTypes` to stay compatible with the behavior
of ClassfileParser. That's a bug, but a separate one and should be fixed
separately.

Also note that this commit updated javac-artifacts.jar, because we need
to test how reflection works with javac-produced classfiles. The sources
that were used to produce those classfiles can be found in the jar next
to the classfiles.
  • Loading branch information...
xeno-by committed Jan 31, 2013
1 parent 309ff57 commit f1701f704a2485fcc2eb6d5d8b5d0228beddd9b3
@@ -1043,13 +1043,7 @@ abstract class ClassfileParser {
val nClasses = in.nextChar
for (n <- 0 until nClasses) {
val cls = pool.getClassSymbol(in.nextChar.toInt)
- val tp = if (cls.isMonomorphicType) cls.tpe else {
- debuglog(s"Encountered polymorphic exception `${cls.fullName}` while parsing class file.")
- // in case we encounter polymorphic exception the best we can do is to convert that type to
- // monomorphic one by introducing existientals, see SI-7009 for details
- typer.packSymbols(cls.typeParams, cls.tpe)
- }
- sym.addAnnotation(appliedType(definitions.ThrowsClass, tp), Literal(Constant(tp)))
+ sym.addThrowsAnnotation(cls)
}
}
@@ -33,6 +33,17 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
case ThrownException(exc) => exc
}
+ def addThrowsAnnotation(excSym: Symbol): Self = {
+ val excTpe = if (excSym.isMonomorphicType) excSym.tpe else {
+ debuglog(s"Encountered polymorphic exception `${excSym.fullName}` while parsing class file.")
+ // in case we encounter polymorphic exception the best we can do is to convert that type to
+ // monomorphic one by introducing existentials, see SI-7009 for details
+ existentialAbstraction(excSym.typeParams, excSym.tpe)
+ }
+ val throwsAnn = AnnotationInfo(appliedType(definitions.ThrowsClass, excTpe), List(Literal(Constant(excTpe))), Nil)
+ withAnnotations(List(throwsAnn))
+ }
+
/** Tests for, get, or remove an annotation */
def hasAnnotation(cls: Symbol): Boolean =
//OPT inlined from exists to save on #closures; was: annotations exists (_ matches cls)
@@ -330,14 +341,14 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
implicit val AnnotationTag = ClassTag[AnnotationInfo](classOf[AnnotationInfo])
object UnmappableAnnotation extends CompleteAnnotationInfo(NoType, Nil, Nil)
-
+
/** Extracts symbol of thrown exception from AnnotationInfo.
- *
+ *
* Supports both “old-style” `@throws(classOf[Exception])`
* as well as “new-stye” `@throws[Exception]("cause")` annotations.
*/
object ThrownException {
- def unapply(ann: AnnotationInfo): Option[Symbol] =
+ def unapply(ann: AnnotationInfo): Option[Symbol] =
ann match {
case AnnotationInfo(tpe, _, _) if tpe.typeSymbol != ThrowsClass =>
None
@@ -610,11 +610,19 @@ private[reflect] trait JavaMirrors extends internal.SymbolTable with api.JavaUni
/**
* Copy all annotations of Java annotated element `jann` over to Scala symbol `sym`.
+ * Also creates `@throws` annotations if necessary.
* Pre: `sym` is already initialized with a concrete type.
* Note: If `sym` is a method or constructor, its parameter annotations are copied as well.
*/
private def copyAnnotations(sym: Symbol, jann: AnnotatedElement) {
sym setAnnotations (jann.getAnnotations map JavaAnnotationProxy).toList
+ // FIXME: we're not using getGenericExceptionTypes here to be consistent with ClassfileParser
+ val jexTpes = jann match {
+ case jm: jMethod => jm.getExceptionTypes.toList
+ case jconstr: jConstructor[_] => jconstr.getExceptionTypes.toList
+ case _ => Nil
+ }
+ jexTpes foreach (jexTpe => sym.addThrowsAnnotation(classSymbol(jexTpe)))
}
/**
@@ -1 +1 @@
-61931a51bb1a2d308d214b96d06e9a8808515dcf ?javac-artifacts.jar
+a05ca69ac68fa7006b1b8ed98597046e105b4047 ?javac-artifacts.jar
@@ -0,0 +1,9 @@
+<init>: List(throws[NullPointerException](classOf[java.lang.NullPointerException]))
+bar: List(throws[Exception](classOf[java.lang.Exception]))
+baz: List(throws[IllegalStateException](classOf[java.lang.IllegalStateException]))
+foo: List(throws[Exception](classOf[java.lang.Exception]))
+=============
+<init>: List(throws[java.lang.NullPointerException](classOf[java.lang.NullPointerException]))
+bar: List(throws[java.lang.Exception](classOf[java.lang.Exception]))
+baz: List(throws[java.lang.IllegalStateException](classOf[java.lang.IllegalStateException]))
+foo: List(throws[java.lang.Exception](classOf[java.lang.Exception]))
@@ -0,0 +1,12 @@
+import language.experimental.macros
+import scala.reflect.macros.Context
+
+object Macros {
+ def impl(c: Context) = {
+ val decls = c.typeOf[JavaClassWithCheckedExceptions[_]].declarations.toList
+ val s = decls.sortBy(_.name.toString).map(decl => (s"${decl.name}: ${decl.annotations}")).mkString(scala.compat.Platform.EOL)
+ c.universe.reify(println(c.literal(s).splice))
+ }
+
+ def foo = macro impl
+}
@@ -0,0 +1,9 @@
+import scala.reflect.runtime.universe._
+
+object Test extends App {
+ Macros.foo
+ println("=============")
+
+ val decls = typeOf[JavaClassWithCheckedExceptions[_]].declarations.toList
+ decls sortBy (_.name.toString) foreach (decl => println(s"${decl.name}: ${decl.annotations}"))
+}

0 comments on commit f1701f7

Please sign in to comment.