Using Java annotations with Java interface implementations in Scala
EDIT: This issue appears to have been resolved as of Scala 2.9.1
Given the following existing Java library (simplified):
public interface IFace<T> {}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Anno {
Class<? extends IFace> value();
}
The library has methods that expect a user defined interface that contains one or more methods annotated with @Anno
.
I'm exploring converting existing code from Java to Scala. The existing codebase contains an implementation of IFace
:
public class Impl implements IFace<String> { }
And I'm trying to create a Scala class that is usable by the library:
trait Usage
{
@Anno(classOf[Impl])
def aMethod(): String
}
The Scala compiler rejects this:
$ scalac -explaintypes Usage.scala
Usage.scala:5: error: type mismatch;
found : java.lang.Class[Impl](classOf[Impl])
required: java.lang.Class[_ <: IFace]
@Anno(classOf[Impl])
^
java.lang.Class[Impl](classOf[Impl]) <: java.lang.Class[_ <: IFace]?
java.lang.Class[Impl](classOf[Impl]) <: java.lang.Class[?0?0]?
java.lang.Class[Impl] <: java.lang.Class[?0?0]?
?0?0 <: Impl?
true
Impl <: ?0?0?
true
true
true
Nothing <: Impl?
<notype> <: Impl?
false
true
Impl <: IFace?
false
java.lang.Class[Impl] <: java.lang.Class[_ <: IFace]?
java.lang.Class[Impl] <: java.lang.Class[?0?0]?
?0?0 <: Impl?
true
Impl <: ?0?0?
true
true
Nothing <: Impl?
<notype> <: Impl?
false
true
Impl <: IFace?
false
false
false
one error found
It appears to be rejecting the code because it doesn't believe that Impl
extends IFace
. Is this a limitation of Java/Scala interoperability, or do I need to specify my use of the Java annotation differently in Scala?
EDIT: The original Java version of Usage
, which compiles, looks like:
public interface Usage
{
@Anno(Impl.class)
String aMethod();
}
I'm trying to find the correct 开发者_如何学运维syntax to say the same thing in Scala.
Example compiles after adding wildcard to Anno
definition:
Class<? extends IFace<?>> value();
I can assume that compiler doesn't treat IFace
like IFace[_]
and doesn't believe that IFace[String]
(and therefore Impl
) extends IFace
.
This is one of these borderline cases where Scala does not inter-operate well with Java. The problem is that a type declared as generics is latter used as a raw type:
public interface IFace<T> {}
// ...
Class<? extends IFace> value();
The most commonly used solution in this case -- and I recommend you look up questions about raw type interaction with Scala, as there were other such cases here on Stack Overflow -- is to write a wrapper in Java.
I'm not sure this would be possible here, but you might try to extend Anno
overriding value
with a compatible type signature. Maybe narrow the return type to Class<? extends Impl>
, or maybe just rewrite it to use generics in IFace
as well.
精彩评论