I have a piece of code that throws java.lang.NoSuchMethodError on runtime that I could not resolve:
private def saveActivationEvent(event: ActivationEvent) = activationEventService.createIfFirst(event)
Implementations:
case class ActivationEvent extends Event
class ActivationEventService extends AbstractEventService[ActivationEvent]
abstract class AbstractExalateEventService[E <: Event] {
def createIfFirst(event: E)(implicit reader: BSONDocumentReader[E], writer: BSONDocumentWriter[E]): Future[Option[BSONObjectID]] = ...
}
I thought it was happening because of the type erasure... Could someone help me to understand the problem?
As I mention in a comment above, any time you see a NoSuchMethodError, the first thing you should check is that your compile and runtime dependency versions match. For what it's worth I can't think of a way that type erasure could have anything to do with a NoSuchMethodError—you may see a ClassCastException if someone has a bad type test that matches because of erasure, but even in that case the problem isn't really the erasure, it's the fact that someone is trying to work around it (and ignored the compiler's warnings).
Related
import scala.reflect.runtime.{universe => ru}
trait someTrait{
def getType[T: ru.TypeTag](obj: T) = ru.typeOf[T]
def reflect()={
println(getType(this)) // got someTrait type, not A type.
}
}
class A extends someTrait{
}
main(){
new A().reflect()
}
When I run main function, I got someTrait type printed out.
How can I get A type in reflect function?
Using TypeTags or ClassTags, you can't (without doing extra work in every subtype, as Ramesh's answer does). Because the compiler inserts them based on static types only.
When it sees getType(this), it first infers type parameter to getType[someTrait](this), and then turns into getType[someTrait](this)(typeTag[someTrait]). You can see A is never considered and it can't be.
As the scala document says, we cant use java reflectoin since it might cause problem.
No, Scala documentation certainly doesn't say you can't use Java reflection for this. You need to understand its limitations but exactly the same applies to Scala reflection.
I'd like to have a base case class I can extend at will into different types. I had something like this working previously, but I must have screwed something up, because now I'm getting compile errors.
trait JobLike
case class Task(name: String) {
def as[T <: JobLike]: Task with T = new Task(this.name) with T
}
The problem is, this gives me a compiler error like this:
java.lang.UnsupportedOperationException: addChild inapplicable for type T
at scala.reflect.internal.Symbols$Symbol.addChild(Symbols.scala:1835)
at scala.tools.nsc.typechecker.Namers$Namer.$anonfun$templateSig$1(Namers.scala:1119)
at scala.tools.nsc.typechecker.Namers$Namer.templateSig(Namers.scala:1107)
at scala.tools.nsc.typechecker.Namers$Namer.classSig(Namers.scala:1178)
at scala.tools.nsc.typechecker.Namers$Namer.memberSig(Namers.scala:1788)
at scala.tools.nsc.typechecker.Namers$Namer.typeSig(Namers.scala:1751)
at scala.tools.nsc.typechecker.Namers$Namer$MonoTypeCompleter.completeImpl(Namers.scala:836)
...
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:82)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:85)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:96)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:101)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)</code>
I swear, I had something working yesterday that basically did just this, but now it's throwing this error.
You managed to hit a compiler bug! While that's certainly an issue, and should be reported, the thing is that your code isn't possible anyway, and it's better that it's crashing and bringing you here than "working" and doing something horribly wrong. Because T can be any subtype of JobLike, there's simply no way to mix it in at compile time. I could very well do trait Boom extends JobLike { def something: Int }; task.as[Boom], and then task couldn't create a Boom because there's no implementation for something.
You can provide asJobLike: Task with JobLike instead of a general as[T]: Task with T, which is completely possible. (Note that it's discouraged to make subtypes of case classes, so you may want to create a new class. The reason is that it breaks the reflexivity of equals.)
Something rather filthy that you can do is call (new Task(this.name) with JobLike).asInstanceOf[Task with T]. asInstanceOf only checks the cast for the leftmost type in the with, so this will not ClassCastException off the bat (you can also do "a".asInstanceOf[String with Int].). It will generally sorta work (modulus asInstanceOf[T] being false) as long as T has no members.
Something horrible that you can also do is use runtime reflection to dynamically create the required class. The trick as a whole is filthy and completely unsafe, so I won't say it here, but have a link.
I work with Spark often, and it would save me a lot of time if the compiler could ensure that a type is serializable.
Perhaps with a type class?
def foo[T: IsSerializable](t: T) = {
// do stuff requiring T to be serializable
}
It's not enough to constrain T <: Serializable. It could still fail at runtime. Unit tests are a good substitute, but you can still forget them, especially when working with big teams.
I think this is probably impossible to do at compile time without the types being sealed.
Yes, it is possible, but not in the way that you're hoping. Your type class IsSerializable could provide a mechanism to convert your T to a value of a type which is guaranteed to be Serializable and back again,
trait IsSerializable[T] {
def toSerializable(t: T): String
def fromSerializable(s: String): Option[T]
}
But, of course, this is just an alternative type class based serialization mechanism in it's own right, making the use of JVM serialization redundant.
Your best course of action would be to lobby Spark to support type class based serialization directly.
I am new to Scala, and I'm running into this problem when I'm trying to unit test some of my interfaces.
I have an InputService trait with method
def poll(parameters: HashMap[String, String]): Option[T]
where T is generic, so InputService has a type parameter [T].
In my module, I have
val inputService: InputService[String] = mock(classOf[InputService[String]])
bind[InputService[String]].toInstance(inputService)
and in my InputServiceTest, I have
var inputService: InputService[String] = _
before {
inputService = Guice.createInjector(new MockWatcherModule).getInstance(classOf[InputService[String]])
}
But the issue is when I run it, it gives me this error
Exception encountered when invoking run on a nested suite - Guice configuration errors:
1) No implementation for services.InputService was bound.
while locating services.InputService
I think it's because it's looking for services.InputService to bound, but it only has services.InputService[String]. However, when I just use InputService instead of InputService[String], I get the error Trait missing Type Parameter.
Any suggestions?
EDIT:
Turns out that I can use typeLiteral from scala-guice and KeyExtensions to solve my issue. Thanks Tavian!
Due to type erasure, in the getInstance(classOf[InputService[String]]) call, you're just passing InputService.class. You need to pass a TypeLiteral instead to encode the generic type information. From a quick Google it looks like
import net.codingwell.scalaguice._
import net.codingwell.scalaguice.InjectorExtensions._
Guice.createInjector(new MockWatcherModule).instance[InputService[String]]
will work.
Why is the "abstract" keyword for class definition optional in Scala, and how do I force the Scala compiler to tell me when my class is abstract?
Here an example that I wrote in Eclipse:
class Toto[T] {
def get(index: Int): T
}
object Toto {
def create[T]: Toto[T] = new Toto[T]
}
This seems to be a perfectly valid class definition in Scala, although it does NOT define the required get method, and is NOT prefixed with abstract. If you don't need the abstract keyword, then why does it exist? And if you want to be told that your class is actually abstract, how do you get the compiler to tell you?
This is not valid scala code, abstract is required, and instanciation forbidden. From the spec (5.2, p63):
The abstract modifier is used in class
definitions. It is redundant for
traits, and mandatory for all other
classes which have incomplete members.
Ab- stract classes cannot be
instantiated (§6.10) with a
constructor invocation unless
followed by mixins and/or a refinement
which override all incomplete members
of the class. Only abstract classes
and traits can have abstract term
members.
The code produces an error in the REPL : error: class Toto needs to be abstract, since method get is not defined
I get the proper behavior with the same message in Eclipse too. You should check whether you get the same error with and without eclipse. Whichever is true, I guess if you have exactly the code you posted without an error (does it run?), a bug repport will be warranted.
To answer my own question: In Eclipse, you can only tell if a class is correct if all other classes compile without errors! In other word, you can't trust anything Eclipse says about a class unless there are no errors in other classes.
So if you have errors in several classes, then there is no way of knowing which ones are the real errors, and neither if a class without errors is correct.
You just have to repeatedly loop on the errors, fixing any one that makes sense, and hoping the others errors that don't make sense are eventually going to just disappear.