【问题标题】:Scala Class Loader for Avro Tools Run Method Written in Java用于 Avro 工具的 Scala 类加载器运行用 Java 编写的方法
【发布时间】:2019-09-30 06:39:43
【问题描述】:

我在确定加载“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")
    }
  }
}

我在调用方法部分似乎有一些问题,但也许整个解决方案有点偏离 - 我需要能够调用该方法以及加载、实例化或...

如何解决这个问题以运行整个代码段(并修复损坏的 avro)?

【问题讨论】:

    标签: java scala avro avro-tools


    【解决方案1】:

    由于您没有包含异常或堆栈跟踪,因此很难说出问题的确切性质。我不确定您为什么要动态加载 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[_]])
    

    要修复调用,您不能在列表中传递参数。调用方法接受可变参数,需要直接传入。

    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

    【讨论】:

    • 谢谢。这有助于我了解有关加载方法的部分。我现在被困在调用部分。边栏:我正在加载 jar,因为另一个代码部分使用旧版本的 avro 库,我需要新版本的工具。
    • 更新为谈话回答调用
    猜你喜欢
    • 2018-06-08
    • 2010-12-11
    • 2019-08-30
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 2014-02-02
    • 1970-01-01
    • 2021-01-29
    相关资源
    最近更新 更多