Github user drewrobb commented on a diff in the pull request:
https://github.com/apache/spark/pull/23062#discussion_r234844306
--- Diff:
sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/ScalaReflection.scala
---
@@ -788,12 +788,37 @@ object ScalaReflection extends ScalaReflection {
}
/**
- * Finds an accessible constructor with compatible parameters. This is a
more flexible search
- * than the exact matching algorithm in `Class.getConstructor`. The
first assignment-compatible
- * matching constructor is returned. Otherwise, it returns `None`.
+ * Finds an accessible constructor with compatible parameters. This is a
more flexible search than
+ * the exact matching algorithm in `Class.getConstructor`. The first
assignment-compatible
+ * matching constructor is returned if it exists. Otherwise, we check
for additional compatible
+ * constructors defined in the companion object as `apply` methods.
Otherwise, it returns `None`.
*/
- def findConstructor(cls: Class[_], paramTypes: Seq[Class[_]]):
Option[Constructor[_]] = {
- Option(ConstructorUtils.getMatchingAccessibleConstructor(cls,
paramTypes: _*))
+ def findConstructor(cls: Class[_], paramTypes: Seq[Class[_]]):
Option[Seq[AnyRef] => Any] = {
+ Option(ConstructorUtils.getMatchingAccessibleConstructor(cls,
paramTypes: _*)) match {
+ case Some(c) => Some((x: Seq[AnyRef]) => c.newInstance(x: _*))
+ case None =>
+ val companion = mirror.staticClass(cls.getName).companion
+ val moduleMirror = mirror.reflectModule(companion.asModule)
+ val applyMethods = companion.asTerm.typeSignature
+ .member(universe.TermName("apply")).asTerm.alternatives
+ applyMethods.find { method =>
+ val params = method.typeSignature.paramLists.head
+ // Check that the needed params are the same length and of
matching types
+ params.size == paramTypes.tail.size &&
+ params.zip(paramTypes.tail).forall { case(ps, pc) =>
+ ps.typeSignature.typeSymbol == mirror.classSymbol(pc)
+ }
+ }.map { applyMethodSymbol =>
+ val expectedArgsCount =
applyMethodSymbol.typeSignature.paramLists.head.size
+ val instanceMirror = mirror.reflect(moduleMirror.instance)
+ val method =
instanceMirror.reflectMethod(applyMethodSymbol.asMethod)
+ (_args: Seq[AnyRef]) => {
+ // Drop the "outer" argument if it is provided
+ val args = if (_args.size == expectedArgsCount) _args else
_args.tail
--- End diff --
You would still have to check the length, in case the first actual argument
was for some reason also a class.
---
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]