在确定加载“ Avro Tools”类及其run
方法的方法时遇到了一些困难。问题出在Java和Scala接口与类加载方法之间。由于avro在Spark应用程序的其他位置使用了不同版本来加载数据文件,因此我需要能够将此特定方法视为对另一版本avro-tools的孤立调用。
以下是我的代码:
package samples
import java.io.{ByteArrayOutputStream, InputStream}
import org.junit.runner.RunWith
import org.specs2.mutable._
import org.specs2.runner._
import scala.collection.JavaConverters._
@RunWith(classOf[JUnitRunner])
class MySpecTest extends Specification {
"Class Loader" should {
"load an implement a class" in {
var classLoader = new java.net.URLClassLoader(
Array(new java.io.File("./avro-tools-1.9.1.jar").toURI.toURL),
this.getClass.getClassLoader)
var clazzDFRT = classLoader.loadClass("org.apache.avro.tool.DataFileRepairTool")
val objDFRT = clazzDFRT.getConstructor().newInstance()
val toolCmdArgsAsJava = List("-o", "all", "questionable.avro", "fixed.avro").asJava
val stdin : InputStream = null
val out: ByteArrayOutputStream = new ByteArrayOutputStream
val stdout = new PrintStream(out) // added stdout in edit#1
val err = System.err
val toolClassArgsAsJava = List(stdin, stdout, // changed out to stdout in edit#1
err, toolCmdArgsAsJava).asJava
// parameterTypes: Class[_] *
// public int run( InputStream stdin, PrintStream out, PrintStream err, List<String> args)
val paramClasses: Array[Class[_]] = Array(classOf[InputStream], classOf[PrintStream], classOf[PrintStream], classOf[java.util.List[_]])
val method = clazzDFRT.getMethod("run", paramClasses : _*)
// the following produces wrong number of arguments exception
method.invoke(objDFRT.asInstanceOf[Object], toolClassArgsAsJava)
// sidebar: is this the end result for the Unit test - want out str with summary
out.toString("UTF-8").contains("File Summary")
}
}
}
我似乎在invoke方法部分中有一些问题,但也许整个解决方案有点不足-我需要能够调用该方法以及加载,实例化或...
如何解决此问题以运行整个代码段(并修复损坏的avro)?
答案 0 :(得分:0)
由于您未包括异常或堆栈跟踪,因此很难说出问题的确切性质。我不确定为什么要动态加载avro工具,而不是在构建过程中静态地包含jar。
// public int run( InputStream stdin, PrintStream out, PrintStream err, List<String> args)
val method = clazzDFRT.getMethod("run", Class[_] : _*)
您没有正确指定参数。
method.invoke(objDFRT.asInstanceOf [Object],toolClassArgsAsJava)
val params: Array[Class[_]] = Array(classOf[InputStream], classOf[PrintStream], classOf[PrintStream], classOf[java.util.List[_]])
val method = clazzDFRT.getMethod("run", params : _*)
或
val method = clazzDFRT.getMethod("run", classOf[InputStream], classOf[PrintStream], classOf[PrintStream], classOf[java.util.List[_]])
要修复调用,您不能在列表中传递参数。 invoke方法采用可变参数,您需要直接传递这些参数。
method.invoke(objDFRT.asInstanceOf[Object], stdin, stdout, stderr, toolCmdArgsAsJava)
或
method.invoke(objDFRT.asInstanceOf[Object], Array(stdin, stdout, stderr, toolCmdArgsAsJava): _*)
请注意,第二个选项使用Array
而不是List
。
我建议您阅读有关在Java和Scala中使用var args的文档 * https://docs.oracle.com/javase/8/docs/technotes/guides/language/varargs.html * http://daily-scala.blogspot.com/2009/11/varargs.html