Question

I'm new to Scala. I need help in resolving this issue.
I have built a project which is written in Scala and I'm trying to integrate it with a Java project. I have taken the dependency on the build scala jar in my Java project in eclipse. However when I call a method in the Scala jar I get ClassCastException when running the application:

Below is the exception I get

Exception in thread "main" java.lang.ClassCastException: com.rockymadden.stringmetric.phonetic.MetaphoneAlgorithm cannot be cast to com.rockymadden.stringmetric.StringFilter at com.rockymadden.stringmetric.phonetic.MetaphoneAlgorithm.compute(MetaphoneAlgorithm.scala:10) at org.gobe.search.dictionary.test.PhoneticTest.main(PhoneticTest.java:16)

What can I do to fix this ?

public static void main(String[] args) {
    MetaphoneMetric metric = new MetaphoneMetric();
    DummyImplicit di = new DummyImplicit();
    MetaphoneAlgorithm algo = new MetaphoneAlgorithm();
    char[] rr = {'h', 'e', 'l', 'l', 'o'};
    System.out.println(algo.compute(rr, di));
}

In the above code "MetaphoneMetric" , "DummyImplicit" are part of Scala Jar I generated.
Logic of Metaphone algorithm can be found at http://pastebin.com/d7CXjDtx

Was it helpful?

Solution 2

Please check this:

Predef.DummyImplicit di = new Predef.DummyImplicit();
MetaphoneAlgorithm algo = MetaphoneAlgorithm.apply();
char[] rr = {'h', 'e', 'l', 'l', 'o'};
System.out.println(Arrays.toString(algo.compute(rr, di).get()));

OTHER TIPS

Looking at the code, your MetaphoneAlgorithm is defined as:

class MetaphoneAlgorithm extends StringAlgorithm[...] { this: StringFilter =>
 ...
}

What is important is this: StringFilter =>. Since StringAlgorithm doesn't already implement StringFilter, mixing this self type is necessary to create a MetaphoneAlgorithm.

In scala you would do:

val algo = new MetaphoneAlgorithm with StringFilter

Edit: as @aim answered, that's exactly what MetaphoneAlgorithm.apply() returns. That is probably what you want.

Or you would create a new class:

class MyAlgo extends MetaphoneAlgorithm with StringFilter

// and then
val algo = new MyAlgo

If you wanted to be able to create a MetaphoneAlgorithm with StringFilter on the java side:

Looking at your StringFilter trait, it should be an interface on the java side.

Edit: Sadly, as it is StringFilter will be turned into an abstract class. The way to provide compatibility with java would be to make StringFilter completely abstract:

trait StringFilter extends Filter[String] with StringFilterable {
  override def filter(charArray: Array[Char]): Array[Char]
}

As well as the Filter trait, and then define MetaphoneAlgorithm.apply() as returning:

def apply(): MetaphoneAlgorithm = new MetaphoneAlgorithm with StringFilter
  with DefaultStringFilter

with DefaultStringFilter being you default StringFilter implementation (the one currently in StringFilter, that also implements the method defined in Filter).

With that change, this becomes possible on the java side:

public class MyAlgo extends MetaphoneAlgorithm implements StringFilter {
  /* implement StringFilter here */
}

And then instantiate that one in your main method.

This is a bit messy, but that allows you to define custom StringFilter implementations on the java side.


The error message itself comes from casting an (unwritten) this to StringFilter, so I can understand why the error is surprising.

As a side note, it is interesting that it lets you directly instantiate the MetaphoneAlgorithm class at all considering it cannot possibly work. I am not sure this can even be prevented, but it is yet another interesting scala/java compatibility problem.

You have defined MetaphoneAlgorithm with a self-type annotation:

class MetaphoneAlgorithm { this: StringFilter =>

This means that the class cannot be used unless it has a StringFilter trait mixed in (e.g. new MetaphoneAlgorithm() with MyCoolStringFilter).

Since you're not doing this in your example, where you're just constructing a plain MetaphoneAlgorithm, the code isn't valid. Scalac would let this compile, but the Java compiler doesn't understand Scala's annotations that tell it why this won't work - so you get your error at runtime.

And in fact I don't think it would be possible to do this at all in pure Java code, since you can't create an anonymous class that mixes in a trait*. If you're going to use Scala classes in Java it makes sense to think about what interface you want Java users to call, and then make sure you don't do anything too Scala-y with it.

*Well, I suppose you probably could if you were really motivated to, but you'd have to look at exact how Scala compiles mixins at the bytecode level and then try to imitate that. It would be horribly brittle and not really worthwhile.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top