Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass nested scala object reference in Java?

There have been some questions answered on this before.

  • How can I pass a scala object reference around in Java
  • How can I use a Scala singleton object in Java?

But my problem is that I have nested scala objects, something like:

object Criteria {
    object ActionCriteria {
        case class Action (parameter: String) {
            def this(parameter: String) = { this(paramerter) }
        }

        object Action {
           def apply(parameter: String): Action = { apply(parameter) }
        } 
    }
}

In java I then need to create a list of Actions. I have tried this... to no avail:

import Criteria.ActionCriteria.Action$

....

List<Criteria.ActionCriteria.Action$.MODULE$> actions = new ArrayList<>();

As well as a bunch of other combinations like adding $.MODULE$ with every object. Right now I am getting the following error:

error: cannot find symbol Criteria.ActionCriteria
like image 962
ferics2 Avatar asked May 09 '26 19:05

ferics2


1 Answers

List<Criteria$ActionCriteria$Action> actions = new ArrayList<>();

Seems to work fine. Found this with Scala REPL:

scala> classOf[Criteria.ActionCriteria.Action]
res1: Class[Criteria.ActionCriteria.Action] = class Criteria$ActionCriteria$Action

If you want the type of Action object, not case class (highly unlikely, but for the sake of completeness):

scala> Criteria.ActionCriteria.Action.getClass
res2: Class[_ <: Criteria.ActionCriteria.Action.type] = class Criteria$ActionCriteria$Action$

The difference is caused by Scala expecting Action to be a type in classOf[Action], so it returns the type corresponding to the case class. When you use Action in a context where a value is expected, it returns the singleton instance instead, so you can call standard Java method getClass to get the type of object Action.

In case you need other types:

Criteria$                       cm    = Criteria$.MODULE$;
Criteria.ActionCriteria$        cacm  = Criteria.ActionCriteria$.MODULE$;
Criteria$ActionCriteria$Action$ cacam = Criteria$ActionCriteria$Action$.MODULE$;
Criteria$ActionCriteria$Action  caca  = new Criteria$ActionCriteria$Action("Foo");

Criteria.ActionCriteria$ is breaking the pattern here. Why? According to Iulian Dragos' comment under bug SI-2034 this is a special case:

since objects are "the equivalent of static" in the Java world, we wanted to make it easier for Java code to use static inner classes. When there's only one level of nesting, there's a guaranteed companion: every top-level object gets a mirror class (if there isn't one) that creates static forwarders to module methods (that's how one can run a main method defined inside an object). Therefore, a special case for one-level nesting: those classes use the flattened name (without a $ suffix) as outer_name. So, Java code can say new Outer.Inner.


Summary

  • For every level of nesting other than first you replace . with $ in your class names

  • If the target type is also an object you add $ at the end

  • If you want an instance you add .MODULE$

like image 97
Paweł Bartkiewicz Avatar answered May 12 '26 08:05

Paweł Bartkiewicz



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!