Skip to content
Closed
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,18 @@ trait ScalaReflection extends Logging {
* only defines a constructor via `apply` method.
*/
private def getCompanionConstructor(tpe: Type): Symbol = {
tpe.typeSymbol.asClass.companion.asTerm.typeSignature.member(universe.TermName("apply"))
def throwUnsupportedOperation = {
throw new UnsupportedOperationException(s"Unable to find constructor for $tpe. " +
s"This could happen if $tpe is an interface, or a trait without companion object " +
"constructor.")
}
tpe.typeSymbol.asClass.companion match {
case NoSymbol => throwUnsupportedOperation
case sym => sym.asTerm.typeSignature.member(universe.TermName("apply")) match {
case NoSymbol => throwUnsupportedOperation
case constructorSym => constructorSym
}
}
}

protected def constructParams(tpe: Type): Seq[Symbol] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ trait ScroogeLikeExample extends Product1[Int] with Serializable {
override def hashCode: Int = x
}

/** Counter-examples to [[ScroogeLikeExample]] as a trait without a companion object constructor */
trait TraitProductWithoutCompanion extends Product1[Int] {}

/** Counter-examples to [[ScroogeLikeExample]] as a trait with no-constructor companion object */
object TraitProductWithNoConstructorCompanion {}

trait TraitProductWithNoConstructorCompanion extends Product1[Int] {}

class ScalaReflectionSuite extends SparkFunSuite {
import org.apache.spark.sql.catalyst.ScalaReflection._

Expand Down Expand Up @@ -404,6 +412,20 @@ class ScalaReflectionSuite extends SparkFunSuite {
StructField("x", IntegerType, nullable = false))), nullable = true))
}

test("SPARK-29026: schemaFor for trait without companion object throws exception ") {
val e = intercept[UnsupportedOperationException] {
schemaFor[TraitProductWithoutCompanion]
}
assert(e.getMessage.contains("Unable to find constructor"))
}

test("SPARK-29026: schemaFor for trait with no-constructor companion throws exception ") {
val e = intercept[UnsupportedOperationException] {
schemaFor[TraitProductWithNoConstructorCompanion]
}
assert(e.getMessage.contains("Unable to find constructor"))
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ Scrolling up, an existing test is for ScroogeLikeExample where it checks that trait with companion object constructor works.


test("SPARK-27625: annotated data types") {
assert(serializerFor[FooWithAnnotation].dataType == StructType(Seq(
StructField("f1", StringType),
Expand Down