I'm trying to implement a generic java interface in scala. I have looked at:
How do I extend Java interface containing generic methods in Scala?
And Scala: Overriding Generic Java Methods II
But still I could not find an answer. Here's the method signature from Spring web:
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
I tried the following in scala:
#throws(classOf[IOException])
#throws(classOf[HttpMessageNotReadableException])
override def read[T](clazz : Class[_ <: T], inputMessage : HttpInputMessage) : T ={
}
But I get an error saying that this method overrides nothing. If I erase the type by doing:
override def read(clazz : Class[_], inputMessage : HttpInputMessage) : AnyRef ={
It marks the method as being overwritten. My question is how can I keep type safety here and force it to override the interface method?
Regards
EDIT
The spring interface:
public interface HttpMessageConverter<T> {
T read(Class<? extends T> clazz,
HttpInputMessage inputMessage)
throws IOException,
HttpMessageNotReadableException
}
I think the problem is likely to be that you have added a type parameter to the read method, rather than using the type parameter from your class declaration:
class MyImpl[T] extends JavaInterface[T] {
override def read(clazz: Class[_ <: T], ... )
}
If we rename your T to U it becomes clearer what you have done:
class MyImpl[T] extends JavaInterface[T] {
/** U is not T */
override def read[U](clazz: Class[_ <: U], ... )
}
You might also try and sing "U is not T" to the tune of REM's Losing My Religion to hammer the point home.
In java you have parameterilized interface, but in scala you try to parameterize method.
Related
I have a generic class that looks like:
class GenericClass[T <: AnyRef] {
def getHash(obj: T): String = obj.toString
}
As you can see, type T needs to have implemented the toString function in order for getHash to work properly. My question: is that possible to apply type bound/constraints so that type T always have toString implemented?
One way that I can think of is to use type class and context bound:
class GenericClass[T : ClassWithToString] {...}
trait ClassWithToString[T] {
def toString(t: T): String
}
implicit object SomeTypeWithToString extends ClassWithToString[SomeType] {
override def toString(a: SomeType): String = a.toString()
}
However, this approach requires clients to define new implicit objects whenever they want to use GenericClass with a new type, which is not ideal in my case. Especially given toString is a very common function that's being implemented by many types. Wanted to get some advice from you on how to solve this issue elegantly!
I have a Lift project with mixed Java-Scala code. The project has a JPA backend written in Java with EclipseLink, which is accessed by the Scala side, which uses Lift and Lift-NG.
On the Java side, I have the following relevant interfaces:
interface IEntity
interface IDAO<T extends IEntity> {
void persist(T t);
}
On the Scala side, I have the following:
abstract class Binding[T <: IEntity] extends NgModel {
def unbind: T
}
class BasicService[B <: Binding[_ <: IEntity]](serviceName: String, dataAccessObject: IDAO[_ <: IEntity]) {
def persist(binding : B): Unit = {
val entity = binding.unbind
dataAccessObject.persist(entity)
}
}
The purpose of this hierarchy is to let me create Service instances which handle a given Binding for entity E, which can also receive and use an appropriate DAO created to handle type E. For example:
// Java side
class Todo implements IEntity
class TodoManager implements IDAO<Todo>
// Scala side
case class TodoBinding extends Binding[Todo] {
override def unbind: Todo = new Todo()
}
object HelloWorld extends BasicService[TodoBinding]("todoService", new TodoManager)
My problem is a compilation error that occurs inside the persist method of BasicService. On the last line, I get this:
Type mismatch: expected _$1, actual: IEntity
As I am a bit inexperienced with Scala, I might be missing something very obvious with the type system, but I genuinely cannot figure this out. How can I work around this error?
Your definition of BasicService does not require that the type argument of B:
B <: Binding[_ <: IEntity]
is compatible with the type argument of dataAccessObject:
dataAccessObject: IDAO[_ <: IEntity]
What if one is Binding[FooEntity] and the other is IDAO[BarEntity]?
You should take that type variable E that you say you are trying to use, and actually define it:
class BasicService[E <: IEntity, B <: Binding[E]]
(serviceName: String, dataAccessObject: IDAO[E])
Also note that in the example code you posted, the type variable B to BasicService might not be necessary, because you only use it to receive the argument binding to persist(). You could have simply used the type Binding[E] there:
class BasicService[E <: IEntity]
(serviceName: String, dataAccessObject: IDAO[E]) {
def persist(binding: Binding[E]): Unit = // ...
}
The question is not about AnyRef.clone(), it is about case with similar semantic.
I'd like to define an interface for classes that may create copy of itself:
trait Cloneable {
def clone() : this.type
}
class Test(val store : Int) extends Cloneable {
def clone() = new Test(store)
}
Path-dependent this.type would not work since this.type is different for the Test class type and for a class extending the Test. The descendant should then override clone method to match its own type.
How should I define type requirement for the Cloneable trait?
I've peeked into scala collections and found here tip: define TestLike trait, that handles type restrictions, and class Test that embodies corresponding trait.
I'd like to avoid unnecessary clumsiness if possible
trying self-recurring pattern as suggested:
trait Cloneable[A <: Cloneable[A]] {
def clone() : A
}
class Store[A <: Cloneable[A]](val store : Int) extends Cloneable[A] {
override def clone() : A = new Store[A](store)
}
failed with error:
Cloneable.scala:6: error: type mismatch;
found : Store[A]
required: A
override def clone() : A = new Store[A](store)
another issue in the recurring template: premature finalization
class Store(val store : Int) extends Cloneable[Store] {
override def clone() = new Store(store)
}
class SubStore(store : Int, val stash : Double) extends Store(store)
val ss1 = new SubStore(1, 0.5)
val ss2 = ss1.clone()
assert(ss2.isInstanceOf[SubStore])
The issue with SubStore is with type system ignoring absent clone() method in the SubStore class although SubStore is the Cloneable descendant via Store. But the Store finalize Cloneable interface with type parameter Store and all its descendants lacks proper clone() method restriction
Scala type variance allows to you implement what you need in a simple way, but you have to move away from inheritance and go to typeclasses.
trait Cloner[A]{
def cloneObject(input:A):A
}
trait CloningFunctions{
def cloneObject[A](input:A)(implicit cloner:Cloner[A]) = cloner.cloneObject(input)
}
object CloningFunctions extends CloningFunctions
class MyClass1(val b:Int)
class MyClass2(val a:Int,b:Int) extends MyClass1(b)
object Example {
implicit val cloner = new Cloner[MyClass1]{
def cloneObject(input: MyClass1): MyClass1 = new MyClass1(input.b)
}
import CloningFunctions._
cloneObject(new MyClass2(3,4))
}
The idea here is that since Cloner[A] is invariant in type A, the following code won't compile:
could not find implicit value for parameter cloner: Cloner[MyClass2]
cloneObject(new MyClass2(3,4))
because you have a Cloner[MyClass1] but not a Cloner[MyClass2] in scope.
While cloneObject(new MyClass1(3)) will compile.
I have been working on an issue with implicit conversion for days now, but somehow I just cannot figure out what I am doing wrong. I read through all the other questions on SO that deal with implicits but I still don't understand what the problem is.
As an example, let's consider a Java interface like this(T extends Object for brevity):
public interface JPersistable<T extends Object> {
public T persist(T entity);
}
In scala, I do the following:
case class A()
case class B() extends A
case class C()
case class D() extends C
trait Persistable[DTOType <: A, EntityType <: C] {
// this would be implemented somewhere else
private def doPersist(source: EntityType): EntityType = source
// this does not implement the method from the Java interface
private def realPersist(source: DTOType)(implicit view: DTOType => EntityType): EntityType = doPersist(source)
// this DOES implement the method from the Java interface, however it throws:
// error: No implicit view available from DTOType => EntityType.
def persist(source: DTOType): EntityType = realPersist(source)
}
case class Persister() extends Persistable[B, D] with JPersistable[B]
object Mappings {
implicit def BToD(source: B): D = D()
}
object Test {
def main(args: Array[String]) {
import Mappings._
val persisted = Persister().persist(B())
}
}
As stated in the comment, I get an exception at compile time. I guess my questions are:
1) Why do I need to specify the implicit conversion on the doRealPersist explicitly? I expected the conversion to happen even if I do the following:
trait Persistable[DTOType <: A, EntityType <: C] {
// this would be implemented somewhere else
private def doPersist(source: EntityType): EntityType = source
def persist(source: DTOType): EntityType = doPersist(source)
}
However, this does not compile either.
2) Why does compilation fail at persist and not at the actual method call (val persisted = Persister().persist(B()))? That should be the first place where the actual type of EntityType and DTOType are known, right?
3) Is there a better way to do what I am trying to achieve? Again, this is not the actual thing I am trying to do, but close enough.
Apologies in advance if this question is ignorant and thanks a lot in advance for your help.
You need to make the conversion available within the trait. You can't pass it in from the outside implicitly because the outside doesn't know that persist secretly requires realPersist which requires an implicit conversion. This all fails even without considering JPersistable.
You can for example add
implicit def view: DTOType => EntityType
as a method in the trait and it will then compile. (You can drop realPersist then also.)
Then you need a way to get that view set. You can
case class Persister()(implicit val view: B => D) extends Persistable[B,D]
and then you're all good. (The implicit val satisfies the implicit def of the trait.)
But now you have bigger problems: your Java interface signature doesn't match your Scala signature. The equivalent Scala is
trait JPersistable[T <: Object] { def persist(t: T): T }
See how persist takes and returns the same type? And see how it does not in your Scala class? That's not going to work, nor should it! So you have to rethink exactly what you're trying to accomplish here. Maybe you just want to make the implicit conversion available--not pass it to the method!--and have Scala apply the implicit conversion for you so that you think you've got a persist that maps from DTOType to EntityType, but you really just have the EntityType to EntityType transform that the Java interface requires.
Edit: for example, here's a working version of what you posted just using standard implicit conversion:
trait JPer[T] { def persist(t: T): T }
class A
case class B() extends A
class C
case class D() extends C
trait Per[Y <: C] extends JPer[Y] {
private def doIt(y: Y): Y = y
def persist(y: Y) = doIt(y)
}
case class Perer() extends Per[D] // "with JPer" wouldn't add anything!
object Maps { implicit def BtoD(b: B): D = D() }
object Test extends App {
import Maps._
val persisted = Perer().persist(B())
}
Pay attention to which types are used where! (Who takes B and who takes D and which direction do you need a conversion?)
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)
}
}