Skip to content

Commit d103e70

Browse files
committed
Go through the context classloader when reflecting on user types in ScalaReflection
Replaced calls to `typeOf` with `typeTag[T].in(mirror)`. The shorter method assumes all types can be found in the classloader that loaded scala-reflect (the primordial classloader). This assumption is not valid in all contexts (sbt console, Eclipse launchers). Fixed SPARK-5281
1 parent 4f87e95 commit d103e70

File tree

1 file changed

+37
-20
lines changed

1 file changed

+37
-20
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/ScalaReflection.scala

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.apache.spark.sql.types._
2727
*/
2828
object ScalaReflection extends ScalaReflection {
2929
val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
30+
val mirror: universe.Mirror = universe.runtimeMirror(Thread.currentThread().getContextClassLoader)
3031
}
3132

3233
/**
@@ -36,6 +37,9 @@ trait ScalaReflection {
3637
/** The universe we work in (runtime or macro) */
3738
val universe: scala.reflect.api.Universe
3839

40+
/** The mirror used to access types in the universe */
41+
val mirror: universe.Mirror
42+
3943
import universe._
4044

4145
// The Predef.Map is scala.collection.immutable.Map.
@@ -52,7 +56,19 @@ trait ScalaReflection {
5256

5357
/** Returns a catalyst DataType and its nullability for the given Scala Type using reflection. */
5458
def schemaFor[T: TypeTag]: Schema =
55-
ScalaReflectionLock.synchronized { schemaFor(typeOf[T]) }
59+
ScalaReflectionLock.synchronized { schemaFor(localTypeOf[T]) }
60+
61+
/**
62+
* Return the Scala Type for `T` in the current classloader mirror.
63+
*
64+
* Use this method instead of the convenience method `universe.typeOf`, which
65+
* assumes that all types can be found in the classloader that loaded scala-reflect classes.
66+
* That's not necessarily the case when running using Eclipse launchers or even
67+
* Sbt console or test (without `fork := true`).
68+
*
69+
* @see SPARK-5281
70+
*/
71+
private def localTypeOf[T: TypeTag]: `Type` = typeTag[T].in(mirror).tpe
5672

5773
/** Returns a catalyst DataType and its nullability for the given Scala Type using reflection. */
5874
def schemaFor(tpe: `Type`): Schema = ScalaReflectionLock.synchronized {
@@ -67,25 +83,25 @@ trait ScalaReflection {
6783
val udt = Utils.classForName(className)
6884
.getAnnotation(classOf[SQLUserDefinedType]).udt().newInstance()
6985
Schema(udt, nullable = true)
70-
case t if t <:< typeOf[Option[_]] =>
86+
case t if t <:< localTypeOf[Option[_]] =>
7187
val TypeRef(_, _, Seq(optType)) = t
7288
Schema(schemaFor(optType).dataType, nullable = true)
7389
// Need to decide if we actually need a special type here.
74-
case t if t <:< typeOf[Array[Byte]] => Schema(BinaryType, nullable = true)
75-
case t if t <:< typeOf[Array[_]] =>
90+
case t if t <:< localTypeOf[Array[Byte]] => Schema(BinaryType, nullable = true)
91+
case t if t <:< localTypeOf[Array[_]] =>
7692
val TypeRef(_, _, Seq(elementType)) = t
7793
val Schema(dataType, nullable) = schemaFor(elementType)
7894
Schema(ArrayType(dataType, containsNull = nullable), nullable = true)
79-
case t if t <:< typeOf[Seq[_]] =>
95+
case t if t <:< localTypeOf[Seq[_]] =>
8096
val TypeRef(_, _, Seq(elementType)) = t
8197
val Schema(dataType, nullable) = schemaFor(elementType)
8298
Schema(ArrayType(dataType, containsNull = nullable), nullable = true)
83-
case t if t <:< typeOf[Map[_, _]] =>
99+
case t if t <:< localTypeOf[Map[_, _]] =>
84100
val TypeRef(_, _, Seq(keyType, valueType)) = t
85101
val Schema(valueDataType, valueNullable) = schemaFor(valueType)
86102
Schema(MapType(schemaFor(keyType).dataType,
87103
valueDataType, valueContainsNull = valueNullable), nullable = true)
88-
case t if t <:< typeOf[Product] =>
104+
case t if t <:< localTypeOf[Product] =>
89105
val formalTypeArgs = t.typeSymbol.asClass.typeParams
90106
val TypeRef(_, _, actualTypeArgs) = t
91107
val constructorSymbol = t.member(nme.CONSTRUCTOR)
@@ -107,19 +123,20 @@ trait ScalaReflection {
107123
schemaFor(p.typeSignature.substituteTypes(formalTypeArgs, actualTypeArgs))
108124
StructField(p.name.toString, dataType, nullable)
109125
}), nullable = true)
110-
case t if t <:< typeOf[String] => Schema(StringType, nullable = true)
111-
case t if t <:< typeOf[java.sql.Timestamp] => Schema(TimestampType, nullable = true)
112-
case t if t <:< typeOf[java.sql.Date] => Schema(DateType, nullable = true)
113-
case t if t <:< typeOf[BigDecimal] => Schema(DecimalType.Unlimited, nullable = true)
114-
case t if t <:< typeOf[java.math.BigDecimal] => Schema(DecimalType.Unlimited, nullable = true)
115-
case t if t <:< typeOf[Decimal] => Schema(DecimalType.Unlimited, nullable = true)
116-
case t if t <:< typeOf[java.lang.Integer] => Schema(IntegerType, nullable = true)
117-
case t if t <:< typeOf[java.lang.Long] => Schema(LongType, nullable = true)
118-
case t if t <:< typeOf[java.lang.Double] => Schema(DoubleType, nullable = true)
119-
case t if t <:< typeOf[java.lang.Float] => Schema(FloatType, nullable = true)
120-
case t if t <:< typeOf[java.lang.Short] => Schema(ShortType, nullable = true)
121-
case t if t <:< typeOf[java.lang.Byte] => Schema(ByteType, nullable = true)
122-
case t if t <:< typeOf[java.lang.Boolean] => Schema(BooleanType, nullable = true)
126+
case t if t <:< localTypeOf[String] => Schema(StringType, nullable = true)
127+
case t if t <:< localTypeOf[java.sql.Timestamp] => Schema(TimestampType, nullable = true)
128+
case t if t <:< localTypeOf[java.sql.Date] => Schema(DateType, nullable = true)
129+
case t if t <:< localTypeOf[BigDecimal] => Schema(DecimalType.Unlimited, nullable = true)
130+
case t if t <:< localTypeOf[java.math.BigDecimal] =>
131+
Schema(DecimalType.Unlimited, nullable = true)
132+
case t if t <:< localTypeOf[Decimal] => Schema(DecimalType.Unlimited, nullable = true)
133+
case t if t <:< localTypeOf[java.lang.Integer] => Schema(IntegerType, nullable = true)
134+
case t if t <:< localTypeOf[java.lang.Long] => Schema(LongType, nullable = true)
135+
case t if t <:< localTypeOf[java.lang.Double] => Schema(DoubleType, nullable = true)
136+
case t if t <:< localTypeOf[java.lang.Float] => Schema(FloatType, nullable = true)
137+
case t if t <:< localTypeOf[java.lang.Short] => Schema(ShortType, nullable = true)
138+
case t if t <:< localTypeOf[java.lang.Byte] => Schema(ByteType, nullable = true)
139+
case t if t <:< localTypeOf[java.lang.Boolean] => Schema(BooleanType, nullable = true)
123140
case t if t <:< definitions.IntTpe => Schema(IntegerType, nullable = false)
124141
case t if t <:< definitions.LongTpe => Schema(LongType, nullable = false)
125142
case t if t <:< definitions.DoubleTpe => Schema(DoubleType, nullable = false)

0 commit comments

Comments
 (0)