views:

376

answers:

3

I'm learning Scala and was curious if it would be possible to:

  1. Create an object which implements a Java interface in Scala
  2. Compile the object into a class file and jar it
  3. Use the object from Java

I want to implement a custom lucene query parser in scala and be able to let others access it from a java application.

+1  A: 

Yes it's possible. Some of the Scala features (such as singleton objects) will compile to code which is hard to use from Java, but using Scala classes through a Java interface is an easy way to write compatible code.

Some questions about Java interoperability are answered at http://www.scala-lang.org/faq/4 and in the book Programming in Scala. Quoted from that FAQ:

Can I use existing Java code from Scala?

Accessing Java classes from Scala code is no problem at all. Using a Scala class from Java can get tricky, in particular if your Scala class uses advanced features like generics, polymorphic methods, or abstract types. Since Java doesn't have such language features, you have to know something about the encoding scheme of Scala classes. Otherwise, there should be no problems.

Do I need to convert Java data structures to Scala, and vice versa?

You do not have to convert Java data structures at all for using them in Scala. You can use them "as is". For instance, Scala classes can subclass Java classes, you can instantiate Java classes in Scala, you can access methods, fields (even if they are static), etc.

Esko Luontola
+12  A: 

I'm assuming that by "object" you actually mean "class". In any case, the answer is yes, you can do this. You will need to take advantage of the Scala/Java joint compiler if you want this all in the same project. For example:

public interface Parser {
    public TokenIterator parse(InputStream is);
}

Then in Scala:

class ParserImpl extends Parser {
  def parse(is: InputStream) = ...
}

Finally, in Java again:

public class Consumer {
    public static void main(String[] args) {
        Parser p = new ParserImpl();       // just like a Java class!
        ...
    }
}

If all of these source files are in the same project, then you will want to compile them using the following invocation of commands:

$ scalac *.scala *.java
$ javac -classpath . *.java

The first command invokes the Scala/Java joint compiler, which will compile the Scala sources and just enough of the Java sources to satisfy any dependencies. The second command invokes the Java compiler with the recently-compiled Scala classes on the classpath.

Daniel Spiewak
+2  A: 

I have implemented a custom org.apache.solr.handler.RequestHandlerBase and custom org.apache.solr.request.QueryResponseWriter in Scala 2.8 with Java 1.6.0 and Solr 1.4.0. I am not sure of the Lucene version Solr 1.4.0 is using but I would assume a fairly recent one. Anyway, I packaged the class files generated by Scala in a jar and Solr was able to load it just fine. So what you are trying to do is possible.

I would say the main thing to overcome is to convert from Java collection objects like List and Vector to Scala collection objects and vice versa. scala.collection.JavaConversions in Scala 2.8.0 will probably be your friend.

One other thing, if you need to override a method like getBooleanQuery, you may need to add [_] to make Scala compile (code not tested - but since it took me a while to figure that kind of stuff out when I started Scala, I thought I'd share):

override def getBooleanQuery(clauses: java.util.List[_]): Query = { ... }

Edit:: One more thing about the joint compilation. Daniel's information on how to joint compile is useful. You may not immediately need it though, as very likely, you just need to have scalac know the path to the Lucene jar files, then package your class in a new jar, and have your jar file used at runtime in the deployed environment.

huynhjl