简体   繁体   中英

Calling overloaded scala case apply from java using java generic

There are several methods I need to write in Java, most of the system is in scala. Interop is not much of an issue except for one case.

I have a java method which takes a generic T in the call to a method, the generic being passed in is actually a scala case class. The challenge I am having is calling the overloaded apply method of the case class from within the java code. It cannot resolve the method apply. I have tried several variations of an extends definition for T but none seem to solve the problem.

Any suggestions? Here is a simplified version of the code so far:

Java (method in question)

public <T> Option<T> getResult(String name) {
    Iterator<Item> items = repo.results(name).iterator();

    if (items.hasNext()) {
        T model = T.apply(items.next());  // ?? how to call overloaded case class apply method
        return new Some<>(model);
    }

    return scala.Option$.MODULE$.apply(null);
}

Scala case class (with overloaded apply method), one of many possible case classes.

case class Person (id: Int, name: String)

object Person {
  def apply(item: Item) = toObject(item)

  def toObject(item: Item): Person = {
    Person(
      item.getProperty[Int]("id"),
      item.getProperty("name")
    )
  }
}

There are two problems in your code:

  1. Java generics are erased at runtime, so in order to do something like T.apply , you'd need an instance of the T , so your method would look like:

    public <T> Option<T> getResult(String name, T t)

  2. You need an upper bound where the apply method would be defined to ensure that you can call the method on T . However, scala declares this in the companion object, which is a separate class from the class it accompanies. And there's no super class for companion objects that describes which apply methods they should implement.

The only thing I could think of is, if you known that the apply method takes only 1 parameter:

public <T> Option<T> getResult(String name, Function1<Item, T> companion){ // this is extended by companion objects of case class that take only 1 parameter
 ... 
  T model = companion.apply(items.next());
 ...
}

With this approach, you'd call the method like this:

 getResult("name", Person$.MODULE$)  //pass the companion object as a factory 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM