4

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.

Christopher Currie
  • 3,025
  • 1
  • 29
  • 40

2 Answers2

2

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.

incrop
  • 2,698
  • 1
  • 18
  • 17
1

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.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • Thanks for this reference, and the suggestion to search on "raw type", which was the keyword I wasn't using when searching earlier. [1] is a SO question that refers to the Scala bug report [2] where Martin Odersky basically says that Scala doesn't understand raw types and they don't want it to. [1] http://stackoverflow.com/questions/4991671/why-does-scala-complain-about-illegal-inheritance-when-there-are-raw-types-in-the [2] https://issues.scala-lang.org/browse/SI-1737 – Christopher Currie Jul 11 '11 at 18:04
  • Also, it looks like this is no longer an issue as of Scala 2.9.1. – Christopher Currie Sep 06 '11 at 16:57
  • @Christopher The type returned by `getClass` returned, but it doesn't look to me like it would make a difference here. – Daniel C. Sobral Sep 06 '11 at 17:13