Skip to content

Commit

Permalink
[SPARK-13067] [SQL] workaround for a weird scala reflection problem
Browse files Browse the repository at this point in the history
A simple workaround to avoid getting parameter types when convert a
logical plan to json.

Author: Wenchen Fan <wenchen@databricks.com>

Closes #10970 from cloud-fan/reflection.
  • Loading branch information
cloud-fan authored and davies committed Jan 29, 2016
1 parent 66449b8 commit 721ced2
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,20 @@ object ScalaReflection extends ScalaReflection {
getConstructorParameters(t)
}

/**
* Returns the parameter names for the primary constructor of this class.
*
* Logically we should call `getConstructorParameters` and throw away the parameter types to get
* parameter names, however there are some weird scala reflection problems and this method is a
* workaround to avoid getting parameter types.
*/
def getConstructorParameterNames(cls: Class[_]): Seq[String] = {
val m = runtimeMirror(cls.getClassLoader)
val classSymbol = m.staticClass(cls.getName)
val t = classSymbol.selfType
constructParams(t).map(_.name.toString)
}

def getClassFromType(tpe: Type): Class[_] = mirror.runtimeClass(tpe.erasure.typeSymbol.asClass)
}

Expand Down Expand Up @@ -745,6 +759,12 @@ trait ScalaReflection {
def getConstructorParameters(tpe: Type): Seq[(String, Type)] = {
val formalTypeArgs = tpe.typeSymbol.asClass.typeParams
val TypeRef(_, _, actualTypeArgs) = tpe
constructParams(tpe).map { p =>
p.name.toString -> p.typeSignature.substituteTypes(formalTypeArgs, actualTypeArgs)
}
}

protected def constructParams(tpe: Type): Seq[Symbol] = {
val constructorSymbol = tpe.member(nme.CONSTRUCTOR)
val params = if (constructorSymbol.isMethod) {
constructorSymbol.asMethod.paramss
Expand All @@ -758,9 +778,6 @@ trait ScalaReflection {
primaryConstructorSymbol.get.asMethod.paramss
}
}

params.flatten.map { p =>
p.name.toString -> p.typeSignature.substituteTypes(formalTypeArgs, actualTypeArgs)
}
params.flatten
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
}

protected def jsonFields: List[JField] = {
val fieldNames = getConstructorParameters(getClass).map(_._1)
val fieldNames = getConstructorParameterNames(getClass)
val fieldValues = productIterator.toSeq ++ otherCopyArgs
assert(fieldNames.length == fieldValues.length, s"${getClass.getSimpleName} fields: " +
fieldNames.mkString(", ") + s", values: " + fieldValues.map(_.toString).mkString(", "))
Expand Down Expand Up @@ -560,7 +560,7 @@ abstract class TreeNode[BaseType <: TreeNode[BaseType]] extends Product {
case obj if obj.getClass.getName.endsWith("$") => "object" -> obj.getClass.getName
// returns null if the product type doesn't have a primary constructor, e.g. HiveFunctionWrapper
case p: Product => try {
val fieldNames = getConstructorParameters(p.getClass).map(_._1)
val fieldNames = getConstructorParameterNames(p.getClass)
val fieldValues = p.productIterator.toSeq
assert(fieldNames.length == fieldValues.length)
("product-class" -> JString(p.getClass.getName)) :: fieldNames.zip(fieldValues).map {
Expand Down

0 comments on commit 721ced2

Please sign in to comment.