Instantiate a Scala class from Java, and use the default parameters of the constructor

It seems, there is no such way: https://issues.scala-lang.org/browse/SI-4278

Issue: default no-args constructor should be generated for classes with all-optional arguments
...

Lukas Rytz: in respect of language uniformity we decided not to fix this one - since it's a problem of interoperability with frameworks, we think it should not be fixed at the language level.

workarounds: repeat a default, or abstract over one, or put one default int the zero-argument constructor

Then Lukas proposes the same solution as you found:

class C(a: A = aDefault, b: B = C.bDefault) {
  def this() { this(b = C.bDefault) }
}
object C { def bDefault = ... }

// OR

class C(a: A = aDefault, b: B) {
  def this() { this(b = bDefault) }
}

There is a solution, please check out section "Default Arguments" from article: https://lampwww.epfl.ch/~michelou/scala/using-scala-from-java.html

It's possible to invoke both constructors and methods by passing the appropriate positional argument from java using .$default$[number] format.

Here scope is as follows:

  • Class constructor: << ClassName >>.init$default$1 for the value of the first arguments default value set in the constructor definition default$2 for second arguments default value and so on.
  • Method call: object.methodName$default$1 to resolve the methods first parameters default value assigned in the method signature etc.

Example:

import za.co.absa.spline.core.SparkLineageInitializer;
SparkLineageInitializer.SparkSessionWrapper lineage = SparkLineageInitializer.SparkSessionWrapper(spark);
lineage.enableLineageTracking(lineage.enableLineageTracking$default$1());

For this example the maven dependency is: groupId: za.co.absa.spline artifactId: spline-core version: 0.3.1


More generally if you have a Scala class with default args and you want to instantiate in Java overriding 0, 1 or more of the defaults without having to specify all, consider extending the Scala API to include a Builder in the companion object.

case class Foo(
  a: String = "a",
  b: String = "b",
  c: String = "c"
)

object Foo {
  class Builder {
    var a: String = "a"
    var b: String = "b"
    var c: String = "c"
    def withA(x: String) = { a = x; this }
    def withB(x: String) = { b = x; this }
    def withC(x: String) = { c = x; this }
    def build = Foo(a, b, c)
  }
}

public class App {
    public static void main(String[] args) {
        Foo f = new Foo.Builder()
            .withA("override a")
            .build();
    }
}

Tags:

Java

Scala