使用反射访问Amazon Deequ中的方法

问题描述

我计划创建一个用户配置文件,稍后将对其进行解析,以便运行来自Amazon Deequ的某些检查。我希望能够从配置文件中传递字符串名称获取方法;但是,在尝试这样做的过程中,我一直遇到障碍。

import com.amazon.deequ.checks._

val ru = scala.reflect.runtime.universe
val rm = ru.runtimeMirror(getClass.getClassLoader)

val myClass = new Check(CheckLevel.Error,"unit testing my data")
val im = rm.reflect(myClass)

val methodSymbolNonNeg = ru.typeOf[Check].decl(ru.TermName("isNonNegative")).asMethod
val methodNonNeg = im.reflectMethod(methodSymbolNonNeg)

Name: Compile Error
Message: <console>:48: error: type mismatch;
 found   : ru.MethodSymbol
 required: ru.MethodSymbol
       val methodNonNeg = im.reflectMethod(methodSymbolNonNeg)

我已经尝试了文档中的一些示例以及在SO上找到的示例。我还检查了类myClass.getClass.getmethods.map(_.getName).foreach{println}和Github中的方法名称

此外,我尝试使用.getClass.getmethod调用方法

val m = myClass.getClass.getmethod("isNonNegative","".getClass,2.13.getClass,Option("").getClass)

Name: java.lang.NoSuchMethodException
Message: com.amazon.deequ.checks.Check.isNonNegative(java.lang.String,double,scala.some)
StackTrace:   at java.lang.class.getmethod(Class.java:1786)

解决方法

无法在您的Scala反射代码中重现编译错误。 使用Scala 2.13.3 + Deequ 1.0.5和Scala 2.11.12 + Deequ 1.0.5可以编译代码。 编写您的依赖关系和Scala版本。尝试清理重建项目(例如,如果使用sbt构建项目,则sbt clean compile)。

Deequ 1.0.5取决于Scala 2的Scala库版本(Shapeless,Twitter Chill,Spark,json4s,scala-parser-combinators,scala-xml,Breeze,Spire,Machinist)。 11 .x,因此您应该使用Scala2。 11 .x。

在Scala 2.13中,我有java.lang.NoClassDefFoundError: scala/Serializable

还请注意,它是在https://github.com/awslabs/deequ上写的

Deequ依赖于Java 8,并且已知可与Apache Spark版本2.2.x至2.4.x一起使用。

您的编译错误 found: ru.MethodSymbol,required: ru.MethodSymbol似乎与依赖版本有关。

关于Java反射代码,您只是错误地指定了方法参数的类。 Check#isNonNegative的签名是

def isNonNegative(
  column: String,assertion: Double => Boolean,hint: Option[String])
: CheckWithLastConstraintFilterable

所以你应该做

myClass.getClass.getMethod("isNonNegative",classOf[String],classOf[Double => Boolean],classOf[Option[_]])

顺便说一下,混合Scala反射和Java反射是很奇怪的。