Using Scala to Override a Java method that uses "? extends" - scala

So I have a Java method:
public abstract List<Class<? extends MyClass>> getListOfClasses();
and I need to override it in Scala. Here is how I am currently doing it:
override def getListOfClasses: java.util.List[Class[_ <: MyClass[_]]] = { null }
However, this does not compile, and I get the error: method getListOfClasses has incompatible type
What am I doing wrong?
EDIT:
MyClass is defined in Java like this:
abstract class MyClass[T] extends MyOtherClass[T] {...}
FINAL EDIT:
As suggested by #AlexeyRomanov below, changing my Java method return type fixed the problem:
public abstract List<Class<? extends MyClass<?>>> getListOfClasses();

It's ugly but asInstanceOf works.
This ugliness comes from Java's inability to express covariance and contra-variance.
Interface:
import java.util.List;
public abstract class Game2J {
public interface MyClass {}
public abstract List<Class<? extends MyClass>> getListOfClasses();
}
Scala code:
import java.util
import Game2J.MyClass
import scala.collection.JavaConverters._
class Game2S extends Game2J {
class MyClass1 extends MyClass
class MyClass2 extends MyClass
override def getListOfClasses: util.List[Class[_ <: MyClass]] =
List(classOf[MyClass1], classOf[MyClass2]).asJava.asInstanceOf[util.List[Class[_ <: MyClass]]]
}
Working example:
public class Game2 {
public static void main(String[] args) {
new Game2S().getListOfClasses().stream().forEach((cl) -> System.out.println(cl.getSimpleName()));
}
}

Related

Why does this subclass have to implement a final method?

I thought putting final in Function would stop this issue from happening? I'm not too familiar with Scala. Can someone explain?
Class 'Country must either be declared abstract or implement abstract member 'execute():Object' in path.to.Invokable'
class Country extends MarketFunction("america") {}
abstract class MarketFunction(function: String) extends Function {
...
}
trait Function extends Invokable {
final def execute(): AnyRef = {
// not important
}
}
public interface Invokable {
Object execute();
}
Is it because AnyRef is not a direct comparison to java Object?
This worked for me
class Country extends MarketFunction("america") {}
abstract class MarketFunction(function: String) extends Function[AnyRef] {
...
}
trait Function[A <: AnyRef] extends Invokable {
override final def execute(): A = {
// not important
}
}
public interface Invokable {
Object execute();
}

Override Java method with arg Class<?> in Scala

I am trying to subclass a class (Y) from an external library that can not be changed. It has a method as such:
protected Object doSomething(Class<?> clazz)
Now in my Scala class (X) I am extending this class and trying to override the method.
override protected def doSomething(clazz: Class[_ <: Object]): AnyRef
However this results in 'Method doSomething overrides nothing'. Changing the code to:
override protected def doSomething(clazz: Class[_]): AnyRef
Stops this error but now when the class is compiled it results in the following error:
class X needs to be abstract, since method doSomething in class Y of type (x$1: Class[_ <: Object])Object is not defined
(Note that Class[_ <: T] does not match Class[_]: their type parameters differ)
Is there any way to achieve this? Scala Version: 2.12.1, Java Version 8.
In the question you did not mention that Object doSomething(Class<?> clazz) method is the implementation of abstract T doSomething(Class<? extends T> clazz) method of abstract generic class.
So actually you have following Java classes (I renamed doSomething to test for brevity):
public abstract class AbstractJava<T> {
protected abstract T test(Class<? extends T> c);
}
public class ConcreteJava extends AbstractJava<Object> {
#Override
protected Object test(Class<?> c) {
return null;
}
}
And you are trying to implement following Scala class:
class ConcreteScala extends ConcreteJava {
override protected def test(c: Class[_]) = super.test(c)
}
But compilation fails because when you try to override test() Scala treats ConcreteJava.test() and AbstractJava.test() methods as if they have different signature.
I found the following workaround.
Create additional Java class that by overriding test() "renames" it to renameTest() and also provides ability to call super ConcreteJava.test() through concreteTest() method.
public abstract class RenameJava extends ConcreteJava {
public Object concreteTest(Class<?> c) {
return super.test(c);
}
abstract protected Object renameTest(Class<?> c);
#Override
protected Object test(Class<?> c) {
return renameTest(c);
}
}
Now in ConcreteScala class you can override renameTest() and you're still able to call super ConcreteJava.test() method using concreteTest() method.
class ConcreteScala extends RenameJava {
override protected def renameTest(c: Class[_]) = {
// custom logic
concreteTest(c)
}
}
In your specific "Spring" case it's implemented in the following way.
RenameGsonHttpMessageConverter.java
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import java.io.IOException;
public abstract class RenameGsonHttpMessageConverter extends GsonHttpMessageConverter {
protected Object superReadInternal(Class<?> clazz, HttpInputMessage inputMessage) throws
IOException, HttpMessageNotReadableException {
return super.readInternal(clazz, inputMessage);
}
abstract protected Object renameReadInternal(Class<?> clazz, HttpInputMessage inputMessage) throws
IOException, HttpMessageNotReadableException;
#Override
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return renameReadInternal(clazz, inputMessage);
}
}
CustomGsonHttpMessageConverter.scala
import org.springframework.http.HttpInputMessage
class CustomGsonHttpMessageConverter extends RenameGsonHttpMessageConverter {
override protected def renameReadInternal(clazz: Class[_], inputMessage: HttpInputMessage) = {
// custom logic
// or you may want to call
superReadInternal(clazz, inputMessage)
}
}
Also I made a bug report SI-10155.

Scala 2.11 override things form an abstract class

I have a question concerning Scala override (as my title suggests)
Now I have the following classes/traits:
trait FSM {def transitionGraph:Map[String,(JsValue,FSM)]
abstract class AClass: FSM { def transitionGraph }
class Class extends AClass{ override def transitionGraph ... } <-- Wont work
trait OverrideTrait extends AClass { abstract override def transitionGraph } <-- works
class NewClass extends OverrideTrait { } <--- Works, I can use the overridden transitionGraph
My question is: Why can I not override things from an abstract class. Is it because I am never allowed to instantiate an abstract class. Thus the behavior :
val AClass class = new Class
is never allowed to happen?
Thanks.
There seems to be a lot of stuff omitted from the code you've given, so I'm not sure I get the question, but here's something similar that does compile:
trait FSM { def transitionGraph: String }
abstract class AClass extends FSM { def transitionGraph: String }
class Class extends AClass { override def transitionGraph = ??? }
trait OverrideTrait extends AClass { override def transitionGraph = ??? }
class NewClass extends OverrideTrait { }
Does this help at all?
Your code example wouldn't compile. But it should work once you corrected a few things:
trait FSM {def transitionGraph:Map[String,(JsValue,FSM)]}
abstract class AbstractClass extends FSM { def transitionGraph }
class ConcreteClass extends AbstractClass{ def transitionGraph = ??? }
val someClass: AbstractClass = new ConcreteClass

abstract class and generics in Scala

i am trying to move my existing app written in java to scala,but i am struggling against
this particular one,.
In java, i have the following abstract class :
public abstract class AbstractHibernateDao<T, ID extends Serializable> extends
HibernateDaoSupport implements GenericDao<T, ID> {
private final Class<? extends T> persistentClass;
public AbstractHibernateDao(Class<? extends T> persistentClass) {
this.persistentClass = persistentClass;
}
I am trying to write that in Scala, but i am struggling with the variable persistentClass, which is of type Class
i have tried the following but it fails big time
abstract class ScalaHibernateDao[T, ID <: Serializable](persistentClass <: T) extends
HibernateDaoSupport with GenericDao[T, ID] {
could anyone assist pls?
w/kindest regards
Marco
You will need to use the specification Class[_ <: T] here to match the Java style:
abstract class ScalaHibernateDao[T, ID <: Serializable](persistentClass: Class[_ <: T]) extends HibernateDaoSupport with GenericDao[T, ID] { ...
I belive the following is idiomatic Scala approach:
abstract class ScalaHibernateDao[T: ClassTag, ID <: Serializable] extends HibernateDaoSupport with GenericDao[T, ID] {
private val persistentClass = classTag[T].runtimeClass
}
When using ClassTags you won't have to pass Class[_] instance manually, the compiler will do it for you:
class SomeEntityDao extends ScalaHibernateDao[SomeEntity, Long]
Class[SomeEntity] then will be automatically resolved.

Scala: Overriding Generic Java Methods II

In Scala, I need to override the following, given, Java classes and methods:
public abstract class AbstractJava<T> {
protected abstract T test(Class<? extends T> clazz);
}
public class ConcreteJava extends AbstractJava<Object> {
#Override
protected Object test(Class<?> clazz) {
return null;
}
}
// Scala
class ConcreteScala extends ConcreteJava {
protected override def test(clazz: Class[_ <: AnyRef]): AnyRef =
super.test(clazz)
}
I'm getting the compilation error:
error: ambiguous reference to overloaded definition,
both method test in class ConcreteJava of type
(clazz: java.lang.Class[_])java.lang.Object
and method test in class AbstractJava of type
(clazz: java.lang.Class[_ <: java.lang.Object])java.lang.Object
match argument types (Class[_$1]) and expected result type AnyRef
super.test(clazz)
I wouldn't expect the Scala compiler to refer to an abstract method on a super call. Also, I'd expect it to refer to the direct super class first.
How can I make the Scala class compile?
Thanks!
Edit:
When leaving off the super.test(clazz) call, there'll be the error message:
error: name clash between defined and inherited member:
method test:(clazz: Class[_ <: AnyRef])AnyRef and
method test:(clazz: java.lang.Class[_])java.lang.Object in class ConcreteJava
have same type after erasure: (clazz: java.lang.Class)java.lang.Object
protected override def test(clazz: Class[_ <: AnyRef]): AnyRef = null
Well, of course these are the same types (or variants) ...! - So there's something wrong with Scala/Java inheritance ...
Thanks to michid, there's a preliminary solution:
class ConcreteScala3 {
this: ConcreteJava =>
protected override def test(clazz: Class[_ <: AnyRef]): AnyRef = {
this.foo() // method of ConcreteJava
null
}
}
although we can't make super calls from here.
Responses are still most welcome.
There are some limitations when overriding Java methods with raw types. See the corresponding Scala ticket. Specifically Martin Odersky's comment: "[...] The only thing one can do in these situations is implement a subclass in Java that implements the method. [...]"
However, I pointed out in a blog post earlier that there seems to be a solution for certain cases. The trick is to explicitly declare the self type of the overriding Scala class using an existential type for the raw type on the Java side.
With this technique I got the following working:
public abstract class AbstractJava<T> {
protected abstract T test(Class<T> clazz);
}
public class ConcreteJava extends AbstractJava<Object> {
#Override
protected Object test(Class<Object> clazz) {
return null;
}
}
class ConcreteScala extends ConcreteJava {
this: AbstractJava[AnyRef] =>
protected override def test(clazz: Class[AnyRef]): AnyRef = {
super.test(clazz)
}
}
The question about the same issue was raised again in 2017.
I think that this is certainly a bug and I created an issue SI-10155.
You can apply the following workaround.
Create additional Java class that by overriding test() "renames" it to renameTest() and also provides ability to call super ConcreteJava.test() through concreteTest() method.
public abstract class RenameJava extends ConcreteJava {
public Object concreteTest(Class<?> c) {
return super.test(c);
}
abstract protected Object renameTest(Class<?> c);
#Override
protected Object test(Class<?> c) {
return renameTest(c);
}
}
Now in ConcreteScala class you can override renameTest() and you're still able to call super ConcreteJava.test() method using concreteTest() method.
class ConcreteScala extends RenameJava {
override protected def renameTest(c: Class[_]) = {
// custom logic
concreteTest(c)
}
}