Skip to content

Commit

Permalink
Wrap findReferencedClasses in try catch (#1694)
Browse files Browse the repository at this point in the history
* Wrap findReferencedClasses in try catch

* Update to catch throwable

* Try specific try catch

* Handle assertion error too
  • Loading branch information
Piyush Narang committed Jun 1, 2017
1 parent 4aeb09f commit dacb39c
Showing 1 changed file with 42 additions and 16 deletions.
@@ -1,11 +1,14 @@
package com.twitter.scalding

import com.twitter.scalding.typed.CoGroupable

import org.slf4j.LoggerFactory
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe.{ Type, TypeRef, Symbol, RuntimeMirror, NullaryMethodType }
import scala.reflect.runtime.universe.{ NullaryMethodType, RuntimeMirror, Symbol, Type, TypeRef }

object ReferencedClassFinder {

private val LOG = LoggerFactory.getLogger(this.getClass)

private val baseContainers = List(
classOf[Execution[_]],
classOf[TypedPipe[_]],
Expand Down Expand Up @@ -36,20 +39,43 @@ object ReferencedClassFinder {
def findReferencedClasses(outerClass: Class[_]): Set[Class[_]] = {
val scalaPackage = Package.getPackage("scala")
val mirror = universe.runtimeMirror(outerClass.getClassLoader)
val scalaType = mirror.classSymbol(outerClass).toType
(for {
field <- outerClass.getDeclaredFields
if baseContainers.exists(_.isAssignableFrom(field.getType))
scalaSignature = scalaType.member(universe.stringToTermName(field.getName)).typeSignature
clazz <- getClassesForType(mirror, scalaSignature)
/* The scala root package contains a lot of shady stuff, eg compile-time wrappers (scala.Int/Array etc),
* which reflection will present as type parameters. Skip the whole package - chill-hadoop already ensures most
* of the ones we care about (eg tuples) get tokenized in cascading.
*/
if !(clazz.isPrimitive || clazz.isArray || clazz.getPackage.equals(scalaPackage))
} yield {
clazz
}).toSet
getClassType(outerClass, mirror) match {
case Some(scalaType) =>
(for {
field <- outerClass.getDeclaredFields
if baseContainers.exists(_.isAssignableFrom(field.getType))
scalaSignature = scalaType.member(universe.stringToTermName(field.getName)).typeSignature
clazz <- getClassesForType(mirror, scalaSignature)
/* The scala root package contains a lot of shady stuff, eg compile-time wrappers (scala.Int/Array etc),
* which reflection will present as type parameters. Skip the whole package - chill-hadoop already ensures most
* of the ones we care about (eg tuples) get tokenized in cascading.
*/
if !(clazz.isPrimitive || clazz.isArray || clazz.getPackage.equals(scalaPackage))
} yield {
clazz
}).toSet
case _ => Set()
}
}

private def getClassType(outerClass: Class[_], mirror: universe.Mirror): Option[universe.Type] = {
try {
Some(mirror.classSymbol(outerClass).toType)
} catch {
// In some cases we fail to find references classes, it shouldn't be fatal.
case r: RuntimeException if r.getMessage.contains("error reading Scala signature") =>
LOG.warn(s"Unable to find referenced classes for: $outerClass. This is potentially due to missing dependencies", r)
None
case t: Throwable if t.getMessage.contains("illegal cyclic reference") =>
// Related to: https://issues.scala-lang.org/browse/SI-10129
LOG.warn(s"Unable to find referenced classes for: $outerClass. Related to Scala language issue: SI-10129", t)
None
case ae: AssertionError if ae.getMessage.contains("no symbol could be loaded from interface") =>
// Related to: https://issues.scala-lang.org/browse/SI-10129
LOG.warn(s"Unable to find referenced classes for: $outerClass. Related to Scala language issue: SI-10129", ae)
None
case t: Throwable => throw t
}
}

private def getClassesForType(mirror: RuntimeMirror, typeSignature: Type): Seq[Class[_]] = typeSignature match {
Expand Down

0 comments on commit dacb39c

Please sign in to comment.