How to create annotations and get them in scala - scala

I want to define some annotations and use them in Scala.
I looked into the source of Scala, found in scala.annotation package, there are some annotations like tailrec, switch, elidable, and so on. So I defined some annotations as them do:
class A extends StaticAnnotation
#A
class X {
#A
def aa() {}
}
Then I write a test:
object Main {
def main(args: Array[String]) {
val x = new X
println(x.getClass.getAnnotations.length)
x.getClass.getAnnotations map { println }
}
}
It prints some strange messages:
1
#scala.reflect.ScalaSignature(bytes=u1" !1* 1!AbCaE
9"a!Q!! 1gn!!.<b iBPE*,7
Ii#)1oY1mC&1'G.Y(cUGCa#=S:LGO/AA!A 1mI!)
Seems I can't get the annotation aaa.A.
How can I create annotations in Scala correctly? And how to use and get them?

FWIW, you can now define scala annotation in scala 2.10 and use reflection to read them back.
Here are some examples:
Reflecting Annotations in Scala 2.10

Could it have something to do with retention? I bet #tailrec is not included in the bytecode getting generated.
If I try to extend ClassfileAnnotation (in order to have runtime retention), Scala tells me that it can't be done, and it has to be done in Java:
./test.scala:1: warning: implementation restriction: subclassing Classfile does not
make your annotation visible at runtime. If that is what
you want, you must write the annotation class in Java.
class A extends ClassfileAnnotation
^

I think you can only define annotations in Java now.
http://www.scala-lang.org/node/106

You can find a nice description of how annotations are to be used in Scala in Programming Scala.
So you can define or use annotations in scala. However there is at least one limitation:
Runtime retention is not quite possible. In theory you should subclass ClassFileAnnotation to achieve this, but currently scalac reports the following warning if you do it:
"implementation restriction: subclassing Classfile does not make your annotation visible at runtime. If that is what you want, you must write the annotation class in Java."
It also means that your code is fine as it is (at least as fine as it is currently possible in Scala), but the annotation is on the class only during compile time. So you could use it e.g. in compiler plugins, but you will not be able to access it runtime.

With scala 2.11.6, this works to extract values of a annotation:
case class MyAnnotationClass(id: String) extends scala.annotation.StaticAnnotation
val myAnnotatedClass: ClassSymbol = u.runtimeMirror(Thread.currentThread().getContextClassLoader).staticClass("MyAnnotatedClass")
val annotation: Option[Annotation] = myAnnotatedClass.annotations.find(_.tree.tpe =:= u.typeOf[MyAnnotationClass])
val result = annotation.flatMap { a =>
a.tree.children.tail.collect({ case Literal(Constant(id: String)) => doSomething(id) }).headOption
}

Related

AbstractMethodError on obscure method name when upgrading from Scala 2.12 to 2.13

I am getting the following error:
java.lang.AbstractMethodError: Receiver class com.pack.ReceiverDAO does not define or inherit an implementation of the resolved method 'abstract void com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq(slick.jdbc.JdbcProfile$API)' of interface com.pack.proj.dao.JSDAO.
when I try to promote my code to Scala 2.13 from 2.12 (the dependency that's giving me issues, com.pack.proj, is compiled by Scala 2.12). I thought an easy way to get rid of this error is to implement a stub for it. However, at the moment, I don't have the source code for com.pack.proj.dao.JSDAO (which is what I extends in my "receiver", com.pack.ReceiverDAO) so I am not sure how to override com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq(slick.jdbc.JdbcProfile$API) w/o compilation errors like "overrides nothing". How can I override this inherited abstract method or otherwise get rid of this runtime error?
For the sake of completeness, I'd like to add that I needed to exclude some of the Scala_2.12-compiled Slick libraries when I declared the troublesome library, com.pack.proj as a dependency:
("com.pack.proj" % "js-dao_2.12" % ProjVer)
.exclude("com.typesafe.slick", "slick-hikaricp_2.12")
.exclude("com.github.tminglei", "slick-pg_2.12")
.exclude("com.typesafe.slick", "slick_2.12")
You simply cannot use a library that is compiled with 2.12 in a 2.13 project. It will inevitably break.
There is no real remedy other than use a version of that library that is compiled with 2.13, or not use it at all.
Make sure you're initialising your database in the same format as recommended. I.e. use a trait to define which extensions you wish to use and then extend this trait on a companion object.
import com.github.tminglei.slickpg._
trait MyPostgresProfile extends ExPostgresProfile
with PgArraySupport {
override val api = MyAPI
object MyAPI extends API with ArrayImplicits {
}
object MyPostgresProfile extends MyPostgresProfile
You can see a more complete example in the slick-pg README

How do you create a ScalaMock stub that doesn't call the constructor of the underlying object?

Consider the following example Scala class and unit test:
class BrokenClass(s: String) {
private val len = s.length
def length(): Int = len
}
class BrokenTest extends FlatSpec with Matchers with MockFactory {
"A BrokenClass" should "stub correctly" in {
val stubThing = stub[BrokenClass]
(stubThing.length _) when () returns (10)
stubThing.length should equal (10)
}
}
In older versions of ScalaMock, this code would work. With Scala 2.12 and ScalaMock 3.6, I'm getting a NullPointerException because even though I'm creating a stub, it's still invoking the "s.length" line of the constructor of BrokenClass. So it's trying to dereference "s", which is null because I haven't passed anything to it because all I want is a stub that returns a specific value when a specific method is called.
Is there a way to create a stub without it trying to invoke the object's constructor? Why did this work in older versions?
ScalaMock generates subclasses using a macro definition.
That macro gets expanded/evaluated during the compiler run.
As mocks are subclasses, the constructors of the superclasses will be called - no exceptions.
You might be able to work around this using some cglib sorcery, but that is not something i am familiar with.
So this may have been possible in older ScalaMock versions but this feature is not coming back anytime soon with the current implementation.
another option is to actually subclass this thing yourself and mock the subclass
class NotSoBrokenClass extends BrokenClass("")
...
val nsb = mock[NotSoBrokenClass]
...
That works in some cases, but if the constructor depends on non-final method calls you'll see funny behaviour (e.g. NPEs) too.

How to do subclass reflection in trait of scala

import scala.reflect.runtime.{universe => ru}
trait someTrait{
def getType[T: ru.TypeTag](obj: T) = ru.typeOf[T]
def reflect()={
println(getType(this)) // got someTrait type, not A type.
}
}
class A extends someTrait{
}
main(){
new A().reflect()
}
When I run main function, I got someTrait type printed out.
How can I get A type in reflect function?
Using TypeTags or ClassTags, you can't (without doing extra work in every subtype, as Ramesh's answer does). Because the compiler inserts them based on static types only.
When it sees getType(this), it first infers type parameter to getType[someTrait](this), and then turns into getType[someTrait](this)(typeTag[someTrait]). You can see A is never considered and it can't be.
As the scala document says, we cant use java reflectoin since it might cause problem.
No, Scala documentation certainly doesn't say you can't use Java reflection for this. You need to understand its limitations but exactly the same applies to Scala reflection.

Why does Scala place a dollar sign at the end of class names?

In Scala when you query an object for either its class or its class name, you'll get a rogue dollar sign ("$") at the tail end of the printout:
object DollarExample {
def main(args : Array[String]) : Unit = {
printClass()
}
def printClass() {
println(s"The class is ${getClass}")
println(s"The class name is ${getClass.getName}")
}
}
This results with:
The class is class com.me.myorg.example.DollarExample$
The class name is com.me.myorg.example.DollarExample$
Sure, it's simple enough to manually remove the "$" at the end, but I'm wondering:
Why is it there?; and
Is there anyway to "configure Scala" to omit it?
What you are seeing here is caused by the fact that scalac compiles every object to two JVM classes. The one with the $ at the end is actually the real singleton class implementing the actual logic, possibly inheriting from other classes and/or traits. The one without the $ is a class containing static forwarder methods. That's mosty for Java interop's sake I assume. And also because you actually need a way to create static methods in scala, because if you want to run a program on the JVM, you need a public static void main(String[] args) method as an entry point.
scala> :paste -raw
// Entering paste mode (ctrl-D to finish)
object Main { def main(args: Array[String]): Unit = ??? }
// Exiting paste mode, now interpreting.
scala> :javap -p -filter Main
Compiled from "<pastie>"
public final class Main {
public static void main(java.lang.String[]);
}
scala> :javap -p -filter Main$
Compiled from "<pastie>"
public final class Main$ {
public static Main$ MODULE$;
public static {};
public void main(java.lang.String[]);
private Main$();
}
I don't think there's anything you can do about this.
Although all answer that mention the Java reflection mechanism are correct this still doesnot solve the problem with the $ sign or the ".type" at the end of the class name.
You can bypass the problem of the reflection with the Scala classOf function.
Example:
println(classOf[Int].getSimpleName)
println(classOf[Seq[Int]].getCanonicalName)
=> int
=> scala.collection.Seq
=> Seq
With this you just have the same result as you have in for example Java
There are several problems with your approach:
You are using Java Reflection. Java Reflection doesn't know anything about Scala.
Furthermore, you are using Java Reflection on a Singleton Object, a concept that doesn't even exist in Java.
Lastly, you are using Java Reflection to ask for the class of a Singleton Object, but in Scala, Singleton Objects aren't instances of a class.
So, in other words: you are asking the wrong language's reflection library to reflect on something it doesn't understand and return something that doesn't even exist. No wonder you are getting nonsense results!
If you use Scala Reflection instead, the results become a lot more sensible:
import scala.reflect.runtime.{universe => ru}
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]
object Foo
val theType = getTypeTag(Foo).tpe
//=> theType: reflect.runtime.universe.Type = Foo.type
As you can see, Scala Reflection returns the correct type for Foo, namely the singleton type (another thing that doesn't exist in Java) Foo.type.
In general, whereas Java Reflection deals mainly in classes, Scala Reflection deals in Types.
Using Scala Reflection instead of Java Reflection is not only better because Java Reflection simply doesn't understand Scala whereas Scala Reflection does (in fact, Scala Reflection is actually just a different interface for calling into the compiler, which means that Scala Reflection knows everything the compiler does), it also has the added benefit that it works on all implementations of Scala, whereas your code would break on Scala.js and Scala-native, which simply don't have Java Reflection.
This is a result of compiling to the JVM. To make an object in scala requires two classes. The "base" class and the class to make the singleton object. Because these classes can't both have the same name, the $ is appended. You could probably modify the compiler so that it won't make a $ but you will still need some way to name the generated class names.

Use `#annotation.varargs` on constructors

I want to declare a class like this:
class StringSetCreate(val s: String*) {
// ...
}
and call that in Java. The problem is that the constructor is of type
public StringSetCreate(scala.collection.Seq)
So in java, you need to fiddle around with the scala sequences which is ugly.
I know that there is the #annotation.varargs annotation which, if used on a method, generates a second method which takes the java varargs.
This annotation does not work on constructors, at least I don't know where to put it. I found a Scala Issue SI-8383 which reports this problem. As far as I understand there is no solution currently. Is this right? Are there any workarounds? Can I somehow define that second constructor by hand?
The bug is already filed as https://issues.scala-lang.org/browse/SI-8383 .
For a workaround I'd recommend using a factory method (perhaps on the companion object), where #varargs should work:
object StringSetCreate {
#varargs def build(s: String*) = new StringSetCreate(s: _*)
}
Then in Java you call StringSetCreate.build("a", "b") rather than using new.