summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Burmako <xeno.by@gmail.com>2012-09-14 21:31:21 +0200
committerEugene Burmako <xeno.by@gmail.com>2012-09-16 19:43:59 +0200
commitcf819b7756de917912807322259ebb993a52ce57 (patch)
tree029fda02a23ddc3051c1ec20aaeebc9dff9913c4
parent24580ac84242679619d27f20258078dd012c120a (diff)
downloadscala-cf819b7756de917912807322259ebb993a52ce57.tar.gz
scala-cf819b7756de917912807322259ebb993a52ce57.tar.bz2
scala-cf819b7756de917912807322259ebb993a52ce57.zip
SI-6356 reflection now supports Java annotations
Except for one thingie: java enums are currently not understood by Scala reflection, hence they aren't yet supported in annotations.
-rw-r--r--src/partest/scala/tools/partest/nest/RunnerManager.scala1
-rw-r--r--src/reflect/scala/reflect/internal/AnnotationInfos.scala1
-rw-r--r--src/reflect/scala/reflect/runtime/JavaMirrors.scala32
-rw-r--r--test/files/run/reflection-java-annotations.check22
-rw-r--r--test/files/run/reflection-java-annotations.jar.desired.sha11
-rw-r--r--test/files/run/reflection-java-annotations.scala20
6 files changed, 75 insertions, 2 deletions
diff --git a/src/partest/scala/tools/partest/nest/RunnerManager.scala b/src/partest/scala/tools/partest/nest/RunnerManager.scala
index 376e0e9bdb..4961424e1b 100644
--- a/src/partest/scala/tools/partest/nest/RunnerManager.scala
+++ b/src/partest/scala/tools/partest/nest/RunnerManager.scala
@@ -217,6 +217,7 @@ class RunnerManager(kind: String, val fileManager: FileManager, params: TestRunP
"-Dpartest.output="+outDir.getAbsolutePath,
"-Dpartest.lib="+LATEST_LIB,
"-Dpartest.reflect="+LATEST_REFLECT,
+ "-Dpartest.comp="+LATEST_COMP,
"-Dpartest.cwd="+outDir.getParent,
"-Dpartest.test-path="+testFullPath,
"-Dpartest.testname="+fileBase,
diff --git a/src/reflect/scala/reflect/internal/AnnotationInfos.scala b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
index 8853b872c0..69e8b9d86f 100644
--- a/src/reflect/scala/reflect/internal/AnnotationInfos.scala
+++ b/src/reflect/scala/reflect/internal/AnnotationInfos.scala
@@ -65,6 +65,7 @@ trait AnnotationInfos extends api.Annotations { self: SymbolTable =>
*/
abstract class ClassfileAnnotArg extends Product
implicit val JavaArgumentTag = ClassTag[ClassfileAnnotArg](classOf[ClassfileAnnotArg])
+ case object UnmappableAnnotArg extends ClassfileAnnotArg
/** Represents a compile-time Constant (`Boolean`, `Byte`, `Short`,
* `Char`, `Int`, `Long`, `Float`, `Double`, `String`, `java.lang.Class` or
diff --git a/src/reflect/scala/reflect/runtime/JavaMirrors.scala b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
index be2661149a..6ddde0618b 100644
--- a/src/reflect/scala/reflect/runtime/JavaMirrors.scala
+++ b/src/reflect/scala/reflect/runtime/JavaMirrors.scala
@@ -9,6 +9,7 @@ import java.lang.reflect.{
Method => jMethod, Constructor => jConstructor, Modifier => jModifier, Field => jField,
Member => jMember, Type => jType, TypeVariable => jTypeVariable, Array => jArray,
GenericDeclaration, GenericArrayType, ParameterizedType, WildcardType, AnnotatedElement }
+import java.lang.annotation.{Annotation => jAnnotation}
import java.io.IOException
import internal.MissingRequirementError
import internal.pickling.ByteCodecs
@@ -572,8 +573,34 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
* 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) {
- // to do: implement
+ private def copyAnnotations(sym: Symbol, jane: AnnotatedElement) {
+ def toAnnotationInfo(jann: jAnnotation): AnnotationInfo = AnnotationInfo(
+ classToScala(jann.annotationType).toType,
+ Nil,
+ // todo. find out the exact order of assocs as they are written in the class file
+ // currently I'm simply sorting the methods to guarantee stability of the output
+ jann.annotationType.getDeclaredMethods.sortBy(_.getName).toList map (m => {
+ def toAnnotArg(value: Any, schema: jClass[_]): ClassfileAnnotArg = {
+ def valueIsConstant =
+ schema.isPrimitive || schema == classOf[String] || schema == classOf[jClass[_]] || schema.isEnum
+
+ def valueAsConstant =
+ if (value == null) null
+ else if (schema.isPrimitive || value.getClass == classOf[String]) value
+ else if (schema == classOf[jClass[_]]) classToScala(value.asInstanceOf[jClass[_]]).toType
+ else if (schema.isEnum) classToScala(value.getClass).typeSignature.declaration(newTermName(value.asInstanceOf[Enum[_]].name))
+ else sys.error(s"not a constant: $value")
+
+ if (valueIsConstant) LiteralAnnotArg(Constant(valueAsConstant))
+ else if (schema.isArray) ArrayAnnotArg(value.asInstanceOf[Array[_]] map (x => toAnnotArg(x, ScalaRunTime.arrayElementClass(schema))))
+ else if (schema.isAnnotation) NestedAnnotArg(toAnnotationInfo(value.asInstanceOf[jAnnotation]))
+ else UnmappableAnnotArg
+ }
+
+ newTermName(m.getName) -> toAnnotArg(m.invoke(jann), m.getReturnType)
+ }))
+
+ sym setAnnotations (jane.getAnnotations map (jann => AnnotationInfo.lazily(toAnnotationInfo(jann)))).toList
}
/**
@@ -612,6 +639,7 @@ trait JavaMirrors extends internal.SymbolTable with api.JavaUniverse { self: Sym
}
override def complete(sym: Symbol): Unit = {
+ if (jclazz.isEnum) throw new ScalaReflectionException("implementation restriction: Java enums are not supported")
load(sym)
completeRest()
}
diff --git a/test/files/run/reflection-java-annotations.check b/test/files/run/reflection-java-annotations.check
new file mode 100644
index 0000000000..84cfd03358
--- /dev/null
+++ b/test/files/run/reflection-java-annotations.check
@@ -0,0 +1,22 @@
+Type in expressions to have them evaluated.
+Type :help for more information.
+
+scala>
+
+scala> import scala.reflect.runtime.universe._
+import scala.reflect.runtime.universe._
+
+scala> val sym = typeOf[Foo].typeSymbol
+sym: reflect.runtime.universe.Symbol = class Foo
+
+scala> sym.typeSignature
+res0: reflect.runtime.universe.Type = java.lang.Object{def <init>(): Foo}
+
+scala> sym.getAnnotations foreach (_.javaArgs)
+
+scala> println(sym.getAnnotations)
+List(ComplexAnnotation(v1 = 1, v10 = "hello", v101 = [101, 101], v102 = [102, 102], v103 = ['g', 'g'], v104 = [104, 104], v105 = [105L, 105L], v106 = [106.0, 106.0], v107 = [107.0, 107.0], v108 = [false, true], v11 = classOf[Foo], v110 = ["hello", "world"], v111 = [classOf[SimpleAnnotation], classOf[ComplexAnnotation]], v113 = [SimpleAnnotation(v1 = 21, v10 = "world2", v11 = classOf[ComplexAnnotation], v2 = 22, v3 = '\027', v4 = 24, v5 = 25L, v6 = 26.0, v7 = 27.0, v8 = false)], v13 = SimpleAnnotation(v1 = 11, v10 = "world1", v11 = classOf[SimpleAnnotation], v2 = 12, v3 = '\r', v4 = 14, v5 = 15L, v6 = 16.0, v7 = 17.0, v8 = false), v2 = 2, v3 = '\03', v4 = 4, v5 = 5L, v6 = 6.0, v7 = 7.0, v8 = false))
+
+scala>
+
+scala>
diff --git a/test/files/run/reflection-java-annotations.jar.desired.sha1 b/test/files/run/reflection-java-annotations.jar.desired.sha1
new file mode 100644
index 0000000000..430e7626e6
--- /dev/null
+++ b/test/files/run/reflection-java-annotations.jar.desired.sha1
@@ -0,0 +1 @@
+c35876a529c6be33bdda7b3f48ac8ae800d2f36a ?reflection-java-annotations.jar
diff --git a/test/files/run/reflection-java-annotations.scala b/test/files/run/reflection-java-annotations.scala
new file mode 100644
index 0000000000..4a4fe2572d
--- /dev/null
+++ b/test/files/run/reflection-java-annotations.scala
@@ -0,0 +1,20 @@
+import scala.tools.partest._
+import scala.tools.nsc.Settings
+
+object Test extends ReplTest {
+ def code = """
+ import scala.reflect.runtime.universe._
+ val sym = typeOf[Foo].typeSymbol
+ sym.typeSignature
+ sym.getAnnotations foreach (_.javaArgs)
+ println(sym.getAnnotations)
+ """
+
+ override def transformSettings(settings: Settings): Settings = {
+ val thisFile = testPath.jfile.getAbsolutePath
+ val javaCompiledAnnotationsJar = (thisFile stripSuffix "scala") + "jar"
+ val classpath = List(sys.props("partest.lib"), sys.props("partest.reflect"), sys.props("partest.comp"), javaCompiledAnnotationsJar) mkString sys.props("path.separator")
+ settings.processArguments(List("-cp", classpath), true)
+ settings
+ }
+} \ No newline at end of file