I want to create an annotation that receives a Class parameter, the example in JAVA should be
#Retention(RUNTIME)
public #interface CustomAnnotation {
Class<Comparable<?>> comparator();
}
I suppose that in Kotlin should be:
#Retention(AnnotationRetention.RUNTIME)
annotation class CustomAnnotation(
val comparator: Class<Comparable<*>>
)
But in Kotlin get an error message Invalid type of annotation member so how should be the equivalent in Kotlin to accept a class as parameter?
See the language reference on annotations:
If you need to specify a class as an argument of an annotation, use a Kotlin class (KClass).
So, instead of Java Class<Comparable<*>>, use the Kotlin equivalent: KClass<Comparable<*>>:
#Retention(AnnotationRetention.RUNTIME)
annotation class CustomAnnotation(
val comparator: KClass<Comparable<*>>
)
Related
I try to create a custom Appender in Scala (to use it in UTs), to migrate log4j1 to log4j2, but i cannot.
in log4j1 it's like:
class TestAppender extends AppenderSkeleton {
}
now i'm doing somting like:
class TestAppender extends AbstractAppender {
}
but i get
Cannot resolve overloaded constructor `AbstractAppender`
Any thoughts on how to do so?
In Java, you call the superclass constructor in your constructor with super(arguments). In Scala, however, because the body of the class (excluding defs) is the default constructor for the class, the superclass constructor is called by passing the arguments in the extends clause:
class TestAppender extends AbstractAppender(...) {
Since the only non-deprecated constructor for AbstractAppender appears to be this one, you almost certainly want something like:
class TestAppender extends AbstractAppender("test", someFilter, someLayout, whetherToIgnoreExceptions, Array()) {
If you want to allow the user of your class to specify a parameter for AbstractAppender, then you would do something like:
class TestAppender(ignoreExceptions: Boolean) extends AbstractAppender("test", someFilter, someLayout, ignoreExceptions, Array()) {
For example, I know that I can add extension to class String like this:
val String.isValidEmail : Boolean
get() {
val expression = "^[\\w\\.-]+#([\\w\\-]+\\.)+[A-Z]{2,4}$"
val pattern = Pattern.compile(expression, Pattern.CASE_INSENSITIVE);
val matcher = pattern.matcher(this)
return matcher.matches()
}
Now I want to add a class as extension into another class, which I think the implementation will be like this:
class Networking {
....
}
class Networking.Email {
....
}
// MainActivity.kt
val email = Networking.Email()
But this gave me error for "Networking.Email". For the "Networking" part: Redeclaration: Networking. For the "Email" part: Expecting a top level declaration. Is this actually possible in Kotlin?
No, there are no such things as extension classes in Kotlin. See here:
Kotlin, similar to C# and Gosu, provides the ability to extend a class
with new functionality without having to inherit from the class or use
any type of design pattern such as Decorator. This is done via special
declarations called extensions. Kotlin supports extension functions
and extension properties.
I want to define a trait that is used by Java code and it would be therefore convenient to have Java-friendly setters and getters for its members. The #BeanProperty annotation does that for me, but I can't get it to work with members that are left undefined in the trait. The following:
import scala.beans.BeanProperty
trait A {
#BeanProperty var useFoo: Boolean
}
yields the warning no valid targets for annotation on method useFoo - it is discarded unused. You may specify targets with meta-annotations, e.g. #(scala.beans.BeanProperty #getter) trait A { #BeanProperty var useFoo: Boolean }
However, it is not discarded unused. A class extending the above trait, for example
class B extends A {
var useFoo = false
}
is correctly rejected by the compiler as it does not implement the getter and setter of the BeanProperty. Annotating the useFoo field in class B with #BeanProperty makes it work as expected. However, this seems not to be the proper way to do this, since the above warning is generated. The documentation for meta annotations suggests that targets are only useful if you want to propagate other annotations onto the generated accessors. So, what is the proper way to define the above trait?
It happens to be a bug in Scala 2.11.x: https://issues.scala-lang.org/browse/SI-8813
My search didn't turn up this issue as in 2.11.1 the warning is "no valid targets for annotation on method", while in 2.11.2 it's "no valid targets for annotation on value"
I'm trying to write a simple BaseDao class using the excellent squeryl ORM framework.
However I've come across a problem when using generic typed keys. I get a compile error when I try and use the '===' operator in my generic BaseDao class. The compile error is: value === is not a member of type parameter TKey
My dao class with its troublesome method is defined as:
import org.squeryl.PrimitiveTypeMode._
import org.squeryl._
abstract class BaseDao[TKey, T <: BaseEntity[TKey]](val table: Table[T]) {
def delete(entity: T) : Boolean = {
table.deleteWhere(record => record.id === entity.id) //This is where I get the compile error
}
}
BaseEntity is defined as:
abstract class BaseEntity[TKey] extends KeyedEntity[TKey]
I import PrimitiveTypeMode in my Dao class too...
My first though was that TKey needed to be constrained to whatever the === operator was constrained to, but on looking at the source, there doesn't seem to be any explicit constraints around the operator, so I'm a bit lost.
The operator is defined in the source of squeryl here: https://github.com/max-l/Squeryl/blob/master/src/main/scala/org/squeryl/dsl/TypedExpression.scala
I don't think this can be done in Squeryl. Squeryl doesn't support generically-typed keys - it uses Java reflection to get their type, which is erased at runtime, and therefore thinks they are of type Object.
I have an object and I need to pass its class to an annotation that takes java.lang.Class, eg:
public #interface PrepareForTest {
Class<?>[] value()
}
object MyObject
#PrepareForTest(Array(?????))
class MySpec ...
I've tried:
#PrepareForTest(Array(classOf[MyObject]))
// error: not found: type MyObject
#PrepareForTest(Array(MyObject))
// error: type mismatch
// found: MyObject.type (with underlying type object MyObject
// required: java.lang.Class[_]
#PrepareForTest(Array(classOf[MyObject.type]))
// error: class type required by MyObject.type found
Not sure what else to try.
classOf[MyObject$] does not work because there is no type called MyObject$.
In fact, the issue did come up before and there is no easy solution. See the discussion on https://lampsvn.epfl.ch/trac/scala/ticket/2453#comment:5
Have a look at the throws annotation:
#throws(classOf[IOException])
The annotation itself is declared as:
class throws(clazz: Class[_]) extends StaticAnnotation
Doing the same for an object does not seem to be possible because scala seems to prevent an object from being viewed as having a class in its own right