How to implement Java interface in Scala with mult

2020-04-05 07:46发布

问题:

I have a Scala class that is trying to implement a Java interface (EntityManager in JavaEE 7 for unit testing purposes to be specific). The interface has these two methods (among others):

public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses);
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings);

In the Scala implementation I have:

override def createStoredProcedureQuery(procedureName: String, resultClasses: Class[_]*): StoredProcedureQuery = ???
override def createStoredProcedureQuery(procedureName: String, resultSetMappings: String*): StoredProcedureQuery = ???

However, I get the following error:

MyTest.scala:134: error: double definition:
method createStoredProcedureQuery:(procedureName: String, resultSetMappings: String*)javax.persistence.StoredProcedureQuery and
method createStoredProcedureQuery:(procedureName: String, resultClasses: Class[_]*)javax.persistence.StoredProcedureQuery at line 133
have same type after erasure: (procedureName: String, resultSetMappings: Seq)javax.persistence.StoredProcedureQuery
override def createStoredProcedureQuery(procedureName: String, resultSetMappings: String*): StoredProcedureQuery = ???

I have not been able to come up with a work around. My Google searches also failed to find and answer. I'm using Scala 2.10.4.

回答1:

AFAIK the EntityManager Java interface cannot be implemented directly in Scala. The Java varargs are converted to Seq[Class[_]] in the first method and Seq[String] in the second method. Because of erasure, both methods then appear as having the same signature createStoredProcedureQuery(String, Seq[_]).

I can only propose a workaround for this issue. You should write a Java abstract class that extends the EntityManager interface and implement the 2 offending methods by delegating to 2 other abstract methods with different names in order to disambiguate:

public abstract class EntityManagerWorkaround implements EntityManager {
@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
    return createStoredProcedureQueryForResultClasses(procedureName, resultClasses);
}

@Override
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
    return createStoredProcedureQueryForResultSetMappings(procedureName, resultSetMappings);
}

public abstract StoredProcedureQuery createStoredProcedureQueryForResultClasses(String procedureName, Class... resultClasses);

public abstract StoredProcedureQuery createStoredProcedureQueryForResultSetMappings(String procedureName, String... resultSetMappings);

}

Now you can extend the abstract class from Scala and implement the disambiguated methods:

class EntityManagerImpl extends EntityManagerWorkaround {
  override def createStoredProcedureQueryForResultClasses(procedureName: String, resultClasses: Class[_]*) = ???

  override def createStoredProcedureQueryForResultSetMappings(procedureName: String, resultSetMappings: String*) = ???
}