Skip to content

scalac considers a Java annotation to be an abstract class when it is an interface #8778

Closed
scala/scala
#6869
@scabug

Description

@scabug

In some cases, it is necessary to implement a Java annotation. For example, Guice provides an implementation of the javax.inject.Named annotation:

https://code.google.com/p/google-guice/source/browse/core/src/com/google/inject/name/NamedImpl.java?name=4.0-beta&r=b7a02b02d81c830d148355c90bc309bcd66fb592&spec=svn359c5c3ec4083dea3dd5060ffc4087d73ff98777

Anything working with Guice may want to similarly provide implementations of other Qualifier annotations, so that the value(s) associated with the annotation can be bound. So the named annotation might be implemented like this in Scala:

@SerialVersionUID(0)
private class NamedImpl(val value: String) extends Named with Serializable {

  // This is specified in java.lang.Annotation.
  override def hashCode: Int = (127 * "value".hashCode) ^ value.hashCode

  override def equals(obj: Any) = obj match {
    case named: Named => value == named.value
    case _ => false
  }

  override def toString: String = s"@${classOf[Named].getName}(value=$value)"

  def annotationType = classOf[Named]
}

However, there is a problem here, scalac considers the Named annotation class to be an abstract class, not an interface, and so makes the annotation the super class, producing the following byte code:

$ javap NamedImpl.class 
Compiled from "NamedImpl.scala"
public class NamedImpl extends javax.inject.Named implements scala.Serializable {
  ...

When this class is loaded, an IncompatibleClassChangeError is raised, since the JVM considers an annotation to be an interface, not an abstract class.

The only way I can find to work around this is to implement the annotation in Java, not Scala.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions