diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..606ca93 --- /dev/null +++ b/build.sbt @@ -0,0 +1,27 @@ +name := "recursivity-commons" + +version := "0.6" + +organization := "com.recursivity" + +scalaVersion := "2.10.4" + +//artifact-name := "bingo" + +resolvers ++= Seq( + "Sonatype OSS Snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/", + "Sonatype OSS Releases" at "https://oss.sonatype.org/content/repositories/releases", + "Novus Salat Snapshots" at "http://repo.novus.com/snapshots", + "Scala-Tools repo" at "http://scala-tools.org/repo-releases/", + "Spring Repo" at "http://maven.springframework.org/milestone", + "Buzz Media" at "http://maven.thebuzzmedia.com", + "Codahale" at "http://repo.codahale.com" +) + +resolvers += "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository" + +libraryDependencies += "org.scalatest" %% "scalatest" % "2.2.4" % "test" + +libraryDependencies += "org.scala-lang" % "scalap" % "2.10.4" + +libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.10.4" \ No newline at end of file diff --git a/project/build.properties b/project/build.properties index 977b879..58e3217 100644 --- a/project/build.properties +++ b/project/build.properties @@ -2,7 +2,7 @@ #Sat Apr 30 19:45:58 BST 2011 project.organization=com.recursivity project.name=recursivity-commons -sbt.version=0.7.7 +sbt.version=0.13.5 project.version=0.6 -build.scala.versions=2.9.1 +build.scala.versions=2.10.4 project.initialize=false diff --git a/src/main/scala/com/recursivity/commons/bean/BeanUtils.scala b/src/main/scala/com/recursivity/commons/bean/BeanUtils.scala index 9c0eb96..f2de73c 100644 --- a/src/main/scala/com/recursivity/commons/bean/BeanUtils.scala +++ b/src/main/scala/com/recursivity/commons/bean/BeanUtils.scala @@ -148,7 +148,7 @@ object BeanUtils { }catch{ case e: InstantiationException => l = new java.util.ArrayList[Any] } - list.foreach(b => l.add(b)) + list.asInstanceOf[List[Any]].foreach(b => l.add(b)) return l } } @@ -187,17 +187,17 @@ object BeanUtils { val listOrSet = cls.newInstance if (classOf[Builder[Any, Any]].isAssignableFrom(cls)) { val builder = listOrSet.asInstanceOf[Builder[Any, Any]] - list.foreach(b => builder += b) + list.asInstanceOf[List[Any]].foreach(b => builder += b) return builder } else if (classOf[LinkedList[_]].isAssignableFrom(cls)) { var seq = listOrSet.asInstanceOf[LinkedList[_]] - list.foreach(elem => { + list.asInstanceOf[List[Any]].foreach(elem => { seq = seq :+ elem }) return seq } else if (classOf[DoubleLinkedList[_]].isAssignableFrom(cls)) { var seq = listOrSet.asInstanceOf[DoubleLinkedList[_]] - list.foreach(elem => { + list.asInstanceOf[List[Any]].foreach(elem => { seq = seq :+ elem }) return seq diff --git a/src/main/scala/com/recursivity/commons/bean/scalap/ScalaSigParser.scala b/src/main/scala/com/recursivity/commons/bean/scalap/ScalaSigParser.scala index 9f59aeb..4568512 100644 --- a/src/main/scala/com/recursivity/commons/bean/scalap/ScalaSigParser.scala +++ b/src/main/scala/com/recursivity/commons/bean/scalap/ScalaSigParser.scala @@ -1,64 +1,93 @@ package com.recursivity.commons.bean.scalap -import scala.tools.scalap.scalax.rules.scalasig._ - - -import tools.scalap._ -import scalax.rules.scalasig.ClassFileParser.{ConstValueIndex, Annotation} -import reflect.generic.ByteCodecs -import java.io.{StringWriter, ByteArrayOutputStream, PrintStream} +import java.io.{StringWriter, PrintStream, OutputStreamWriter, ByteArrayOutputStream} +import scala.reflect.NameTransformer +import scala.tools.scalap._ +import scalax.rules.scalasig._ /** - * This file is largely an extended retro-fit of scala.tools.scalap.Main from the scalap.jar of the Scala - * distribution, hence copyrights and kudos to all the people involved in that. I have merely made it slightly more - * usable within an application context, rather than as a command line tool, and added functions for parsing the output. - * - * Scala classfile decoder - * c) 2003-2010, LAMP/EPFL - * http://scala-lang.org/ - * - * @author Matthias Zenger, Stephane Micheloud, Burak Emir, Ilya Sergey, Wille Faler - */ +* This file is largely an extended retro-fit of scala.tools.scalap.Main from the scalap.jar of the Scala +* distribution, hence copyrights and kudos to all the people involved in that. I have merely made it slightly more +* usable within an application context, rather than as a command line tool, and added functions for parsing the output. +* +* Scala classfile decoder +* c) 2003-2010, LAMP/EPFL +* http://scala-lang.org/ +* +* @author Matthias Zenger, Stephane Micheloud, Burak Emir, Ilya Sergey, Wille Faler +*/ object ScalaSigParser { - val SCALA_SIG = "ScalaSig" + val SCALA_SIG = "ScalaSig" val SCALA_SIG_ANNOTATION = "Lscala/reflect/ScalaSignature;" - val BYTES_VALUE = "bytes" + val BYTES_VALUE = "bytes" - /* val versionMsg = "Scala classfile decoder " + - Properties.versionString + " -- " + + /* val versionMsg = "Scala classfile decoder " + + Properties.versionString + " -- " + Properties.copyrightString + "\n" */ var printPrivates = false + def isScalaFile(bytes: Array[Byte]): Boolean = { + val byteCode = ByteCode(bytes) + val classFile = ClassFileParser.parse(byteCode) + classFile.attribute("ScalaSig").isDefined + } - def processJavaClassFile(clazz: Classfile): String = { + /**Processes the given Java class file. + * + * @param clazz the class file to be processed. + */ + def processJavaClassFile(clazz: Classfile) = { val out = new StringWriter + /// / construct a new output stream writer //val out = new OutputStreamWriter(Console.out) val writer = new JavaWriter(clazz, out) // print the class writer.printClass out.flush() - return writer.toString + writer.toString() } - def process(classname: String): String = { - val encName = Names.encode( - if (classname == "scala.AnyRef") "java.lang.Object" - else classname) - val name = "/" + encName.replace(".", "/") + ".class" - val resource = this.getClass.getResourceAsStream(name) + def isPackageObjectFile(s: String) = s != null && (s.endsWith(".package") || s == "package") - val bytes = readToBytes(resource) + def parseScalaSignature(scalaSig: ScalaSig, isPackageObject: Boolean) = { + val baos = new ByteArrayOutputStream + val stream = new PrintStream(baos) + val syms = scalaSig.topLevelClasses ++ scalaSig.topLevelObjects - if (isScalaFile(bytes)) { - return decompileScala(bytes, isPackageObjectFile(classname)) - } else { - // construct a reader for the classfile content - val reader = new ByteArrayReader(bytes) //cfile.toByteArray) - // parse the classfile - val clazz = new Classfile(reader) - return processJavaClassFile(clazz) + syms.head.parent match { + // Partial match + case Some(p) if (p.name != "") => { + val path = p.path + if (!isPackageObject) { + stream.print("package "); + stream.print(path); + stream.print("\n") + } else { + val i = path.lastIndexOf(".") + if (i > 0) { + stream.print("package "); + stream.print(path.substring(0, i)) + stream.print("\n") + } + } + } + case _ => + } + // Print classes + val printer = new ScalaSigPrinter(stream, printPrivates) + syms foreach (printer printSymbol _) + baos.toString + } + + def decompileScala(bytes: Array[Byte], isPackageObject: Boolean): String = { + val byteCode = ByteCode(bytes) + val classFile = ClassFileParser.parse(byteCode) + + scala.tools.scalap.scalax.rules.scalasig.ScalaSigParser.parse(classFile) match { + case Some(scalaSig) => parseScalaSignature(scalaSig, isPackageObject) + case None => "" } } @@ -79,71 +108,36 @@ object ScalaSigParser { bytes } - def isPackageObjectFile(s: String) = s != null && (s.endsWith(".package") || s == "package") - - - def decompileScala(bytes: Array[Byte], isPackageObject: Boolean): String = { - val byteCode = ByteCode(bytes) - val classFile = ClassFileParser.parse(byteCode) - classFile.attribute(SCALA_SIG).map(_.byteCode).map(ScalaSigAttributeParsers.parse) match { - // No entries in ScalaSig attribute implies that the signature is stored in the annotation - case Some(ScalaSig(_, _, entries)) if entries.length == 0 => unpickleFromAnnotation(classFile, isPackageObject) - case Some(scalaSig) => parseScalaSignature(scalaSig, isPackageObject) - case None => "" + /** Executes scalap with the given arguments and classpath for the + * class denoted by `classname`. + */ + def process(classname: String) = { + // find the classfile + val encName = classname match { + case "scala.AnyRef" => "java.lang.Object" + case _ => + // we have to encode every fragment of a name separately, otherwise the NameTransformer + // will encode using unicode escaping dot separators as well + // we can afford allocations because this is not a performance critical code + classname.split('.').map(NameTransformer.encode).mkString(".") } - } - def isScalaFile(bytes: Array[Byte]): Boolean = { - val byteCode = ByteCode(bytes) - val classFile = ClassFileParser.parse(byteCode) - classFile.attribute("ScalaSig").isDefined - } + val name = "/" + encName.replace(".", "/") + ".class" + val resource = this.getClass.getResourceAsStream(name) + val bytes = readToBytes(resource) - def unpickleFromAnnotation(classFile: ClassFile, isPackageObject: Boolean): String = { - import classFile._ - classFile.annotation(SCALA_SIG_ANNOTATION) match { - case None => "" - case Some(Annotation(_, elements)) => - val bytesElem = elements.find(elem => constant(elem.elementNameIndex) == BYTES_VALUE).get - val bytes = ((bytesElem.elementValue match { - case ConstValueIndex(index) => constantWrapped(index) - }) - .asInstanceOf[StringBytesPair].bytes) - val length = ByteCodecs.decode(bytes) - val scalaSig = ScalaSigAttributeParsers.parse(ByteCode(bytes.take(length))) - parseScalaSignature(scalaSig, isPackageObject) + if (isScalaFile(bytes)) { + decompileScala(bytes, isPackageObjectFile(encName)) + } else { + // construct a reader for the classfile content + val reader = new ByteArrayReader(bytes) + // parse the classfile + val clazz = new Classfile(reader) + processJavaClassFile(clazz) } - } - def parseScalaSignature(scalaSig: ScalaSig, isPackageObject: Boolean) = { - val baos = new ByteArrayOutputStream - val stream = new PrintStream(baos) - val syms = scalaSig.topLevelClasses ::: scalaSig.topLevelObjects - syms.head.parent match { - //Partial match - case Some(p) if (p.name != "") => { - val path = p.path - if (!isPackageObject) { - stream.print("package "); - stream.print(path); - stream.print("\n") - } else { - val i = path.lastIndexOf(".") - if (i > 0) { - stream.print("package "); - stream.print(path.substring(0, i)) - stream.print("\n") - } - } - } - case _ => - } - // Print classes - val printer = new ScalaSigPrinter(stream, printPrivates) - for (c <- syms) { - printer.printSymbol(c) - } - baos.toString } } + +