diff options
author | James Iry <james.iry@typesafe.com> | 2013-05-29 14:10:02 -0700 |
---|---|---|
committer | James Iry <james.iry@typesafe.com> | 2013-05-29 14:19:25 -0700 |
commit | fc6da8d8b765ddc3c492d0884164561ca7a8b4d8 (patch) | |
tree | 65c6301aef6880e456f97d59df1bcfefce66db4a | |
parent | 9eb63c522fc3f490ff8ff3e731dca1e160a0338f (diff) | |
download | scala-fc6da8d8b765ddc3c492d0884164561ca7a8b4d8.tar.gz scala-fc6da8d8b765ddc3c492d0884164561ca7a8b4d8.tar.bz2 scala-fc6da8d8b765ddc3c492d0884164561ca7a8b4d8.zip |
Test for reading JDK 8 (classfile format 52) class files.
This commit includes a test for reading JDK 8 (classfile format 52)
class files, in particular default (aka defender) methods. It uses ASM
to generate an interface with default methods then exercises that
interface from Scala.
Surprisingly no changes are necessary to the Scala code base to support
reading format 52 class files.
Because the test can only run under JDK 8, the JDK version is checked
and the expected output is synthesized for previous versions.
-rw-r--r-- | test/files/run/classfile-format-52.check | 2 | ||||
-rw-r--r-- | test/files/run/classfile-format-52.scala | 80 |
2 files changed, 82 insertions, 0 deletions
diff --git a/test/files/run/classfile-format-52.check b/test/files/run/classfile-format-52.check new file mode 100644 index 0000000000..5d24ef03cc --- /dev/null +++ b/test/files/run/classfile-format-52.check @@ -0,0 +1,2 @@ +hello from publicMethod +hello from staticMethod diff --git a/test/files/run/classfile-format-52.scala b/test/files/run/classfile-format-52.scala new file mode 100644 index 0000000000..f0ad7c2ed6 --- /dev/null +++ b/test/files/run/classfile-format-52.scala @@ -0,0 +1,80 @@ +import java.io.{File, FileOutputStream} + +import scala.tools.nsc.settings.ScalaVersion +import scala.tools.partest._ +import scala.tools.asm +import asm.{AnnotationVisitor, ClassWriter, FieldVisitor, Handle, MethodVisitor, Opcodes} +import Opcodes._ + +// This test ensures that we can read JDK 8 (classfile format 52) files, including those +// with default methods. To do that it first uses ASM to generate an interface called +// HasDefaultMethod. Then it runs a normal compile on Scala source that extends that +// interface. Any failure will be dumped to std out. +// +// By it's nature the test can only work on JDK 8+ because under JDK 7- the +// interface won't verify. +object Test extends DirectTest { + override def extraSettings: String = "-optimise -usejavacp -d " + testOutput.path + " -cp " + testOutput.path + + def generateInterface() { + val interfaceName = "HasDefaultMethod" + val methodType = "()Ljava/lang/String;" + + val cw = new ClassWriter(0) + cw.visit(52, ACC_PUBLIC+ACC_ABSTRACT+ACC_INTERFACE, interfaceName, null, "java/lang/Object", null) + + def createMethod(flags:Int, name: String) { + val method = cw.visitMethod(flags, name, methodType, null, null) + method.visitCode() + method.visitLdcInsn(s"hello from $name") + method.visitInsn(ARETURN) + method.visitMaxs(1, 1) + method.visitEnd() + } + + createMethod(ACC_PUBLIC, "publicMethod") + createMethod(ACC_PUBLIC+ACC_STATIC, "staticMethod") + createMethod(ACC_PRIVATE, "privateMethod") + + cw.visitEnd() + val bytes = cw.toByteArray() + + val fos = new FileOutputStream(new File(s"${testOutput.path}/$interfaceName.class")) + try + fos write bytes + finally + fos.close() + + } + + def code = +""" +class Driver extends HasDefaultMethod { + println(publicMethod()) + println(HasDefaultMethod.staticMethod()) +} +""" + + override def show(): Unit = { + // redirect err to out, for logging + val prevErr = System.err + System.setErr(System.out) + try { + // this test is only valid under JDK 1.8+ + // cheat a little by using 'ScalaVersion' because it can parse java versions just as well + val requiredJavaVersion = ScalaVersion("1.8") + val executingJavaVersion = ScalaVersion(System.getProperty("java.specification.version")) + if (executingJavaVersion >= requiredJavaVersion) { + generateInterface() + compile() + Class.forName("Driver").newInstance() + } else { + // under other versions just dump the expected results + println("hello from publicMethod") + println("hello from staticMethod") + } + } + finally + System.setErr(prevErr) + } +} |