You can try to make registeredAllMethod a macro
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Macros {
def registeredAllMethod(className:String): Unit = macro registeredAllMethodImpl
def registeredAllMethodImpl(c: blackbox.Context)(className:c.Tree): c.Tree = {
import c.universe._
val classNameStr = c.eval(c.Expr[String](className))
val moduleSymbol = c.mirror.staticModule(classNameStr)
val calls = moduleSymbol.typeSignature.decls.toList
.filter(decl => decl.isMethod && !decl.isConstructor)
.map(methodSymbol =>
q"sparkSession.udf.register(${methodSymbol.name.toString}, $methodSymbol _)"
)
q"..$calls"
}
}
https://gist.github.com/DmytroMitin/0f8d044d839756dd68ee901703e68ee6
Other options don't seem to work:
- Scala toolbox produces
java.lang.ClassCastException: cannot assign instance of java.lang.invoke.SerializedLambda to field org.apache.spark.sql.catalyst.expressions.ScalaUDF.f of type scala.Function1 in instance of org.apache.spark.sql.catalyst.expressions.ScalaUDF
https://gist.github.com/DmytroMitin/615e7420b7de5d209c0631f269129f9a
- Real Scala compiler behaves similarly
https://gist.github.com/DmytroMitin/28936be58ba943d7771d7d4ede58abff
- Java reflection (with
LambdaMetafactory) produces org.apache.spark.SparkException: Task not serializable, Caused by: java.io.NotSerializableException: App$$$Lambda$994/768702707
https://gist.github.com/DmytroMitin/387e75ed39148fc8e70839584392d946
- Scala reflection (with toolbox) also produces one of the above two exceptions depending on whether we feed to
.register a lambda or an instance of anonymous class
https://gist.github.com/DmytroMitin/2a292d35f3c3ac5cf96d22dd81721366
Something in Spark reflection breaks. So macros seem to be the best option.
Actually I managed to fix "Java reflection" approach but it's not so easy
https://gist.github.com/DmytroMitin/68909e971141f442f75fa09c46f69b16
The trick is to create new FunctionN with Serializable {...}. But I didn't manage to do this with runtime compilation (e.g. with reflective toolbox; whatever I do I receive a lambda rather than an instance of a class), only with bytecode manipulation (with Javassist).
Macros seem to be easier.
Also you can make defs in your objects vals and then serialization issues should disappear
https://gist.github.com/DmytroMitin/4000bfc43cb1343578c4dc5d18acf6dc