I am trying to use the Deequ library from Java, and am having issue using the following method:
def hasCompleteness(
column: String,
assertion: Double => Boolean,
hint: Option[String] = None)
: CheckWithLastConstraintFilterable = {
addFilterableConstraint { filter => completenessConstraint(column, assertion, filter, hint) }
}
In particular, for the assertion, I need to pass in a Function1<Double, Boolean>
So I use the following code to create an assertion function in Java:
public static Function1<Double, Boolean> atLeast(double thresholdPercentage) {
return new scala.compat.java8.functionConverterImpls.FromJavaFunction<>((Double actualPercentage) -> actualPercentage >= thresholdPercentage);
}
Simple enough, right?
Only, my Java Class now won't compile because the signature of the hasCompleteness
method, when viewed from Java is that the assertion parameter is a Function1<Object, Object>
. Thus I see the following error:
Required type: Function1<Object, Object>
Provided: Function1<Double, Boolean>
If I change my atLeast
method to return an unparametrized Function1
the issue goes away, but this feels like an ugly kludge.
Am I condemned to losing the type params when using this method from Java? Or is there something perhaps wrong with my IntelliJ / Gradle setup causing this weird behavior?
CodePudding user response:
That seems how Scala compiler translates "primitive" Scala types (remember, Double
here is scala.Double
and not java.lang.Double
). E.g. Scala declarations
var d: Double => Boolean;
var s: String => String;
produce (as shown by javap):
public abstract scala.Function1<java.lang.Object, java.lang.Object> d();
public abstract scala.Function1<java.lang.String, java.lang.String> s();
Note how Double
and Boolean
both translate to Object
, but String
is preserved
CodePudding user response:
peterz detailed exactly what happens under the hood.
Sounds like what you need is an explicit conversion from the primitive double
Java predicate (java.util.function.DoublePredicate
) to the scala.Double
Scala predicate (Double => Boolean
).
Scala actually offers one such conversion called FromJavaDoublePredicate
.
The code does not require explicit Double
cast anymore:
/* some scala file */
def hasCompleteness(
x: Double,
f: Double => Boolean
): Unit = println(f(x))
/* some java file */
public static FromJavaDoublePredicate atLeast(double thresholdPercentage) {
return new scala.compat.java8.functionConverterImpls.FromJavaDoublePredicate(
actualPercentage -> actualPercentage >= thresholdPercentage);
}
FromJavaDoublePredicate f = atLeast(3.0);
Test.hasCompleteness(5, f); // true
PS. From what I saw, you chose scala-java8-compat, so I assumed you use an earlier version of Scala. Their maintainers state:
If you are using Scala 2.13 or newer only, then don't use this library! Use the classes under
scala.jdk
instead; they were added to the standard library in 2.13.
So for Scala 2.13.x I recommend using the FromJavaDoublePredicate case class in the FunctionWrappers
object instead.