Github user srowen commented on a diff in the pull request:

    https://github.com/apache/spark/pull/23062#discussion_r234833024
  
    --- 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 --
    
    I guess we could check whether the dropped arg is of the type of the Class 
argument to be safer, but this probably works


---

---------------------------------------------------------------------
To unsubscribe, e-mail: reviews-unsubscr...@spark.apache.org
For additional commands, e-mail: reviews-h...@spark.apache.org

Reply via email to