Scala implicitly extend an interface - scala

How can I make arbitrary type T to conform to trait Run without having inherit the trait? Type class works at method level but class is expecting type Run and I cannot change method signature of run() as it is overriding an interface.
trait Run[T] {
def run(): Unit
}
class SomeClass(runner: Run[_]) extends Runnable {
#override def run() {
runner.run()
}
}
Current solution:
class SomeRunnable(someRunnable: SomeType) {
#override def run(){
someRunabble.someMethod()
}
}

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. Making a class generic

I have this code which appears over and over in my project for each type of class we serialize to Avro
class FooKryoRegistrator extends KryoRegistrator {
override def registerClasses(kryo: Kryo) {
kryo.register(classOf[Foo], SpecificRecordBinarySerializer(classTag[Foo]))
kryo.register(classOf[GenericData.Array[_]], new SpecificInstanceCollectionSerializer(classOf[java.util.ArrayList[_]]))
}
}
Now instead of having to write this Registrator class for each and every entity (Foo, Bar, Baz.....) in my project, I thought it will be better to make this generic. So I did
class GenericKryoRegistrator[T] extends KryoRegistrator {
override def registerClasses(kryo: Kryo) {
kryo.register(classOf[T], SpecificRecordBinarySerializer(classTag[T]))
kryo.register(classOf[GenericData.Array[_]], new SpecificInstanceCollectionSerializer(classOf[java.util.ArrayList[_]]))
}
}
But I get a compile time error
class type required but T found
I googled on this error and found a recommendation that I should use ClassTag instead of class. So I changed the implementation to
class GenericKryoRegistrator[T] extends KryoRegistrator {
override def registerClasses(kryo: Kryo) {
kryo.register(classTag[T].runtimeClass, SpecificRecordBinarySerializer(classTag[T]))
kryo.register(classOf[GenericData.Array[_]], new SpecificInstanceCollectionSerializer(classOf[java.util.ArrayList[_]]))
}
}
but now it says
No ClassTag available for T
If you take the class tag as an implicit argument to your class, you can then use it:
class GenericKryoRegistrator[T] (implicit ct: ClassTag[T]) extends KryoRegistrator {
override def registerClasses(kryo: Kryo) {
kryo.register(ct.runtimeClass, SpecificRecordBinarySerializer(ct))
kryo.register(classOf[GenericData.Array[_]], new SpecificInstanceCollectionSerializer(classOf[java.util.ArrayList[_]]))
}
}

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

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)
}
}