How to eval code that uses InterfaceStability annotation (that fails with “illegal cyclic reference involving class InterfaceStability”)?

后端 未结 1 1971
离开以前
离开以前 2020-12-19 19:26

I want to dynamically generate some kafka stream code when the program is running, but I get an exception when I compile the following code for kafka stream with scala toolb

1条回答
  •  失恋的感觉
    2020-12-19 20:26

    After switching to the api below the scala.tools.nsc package, I can compile successfully.

    refer to https://eknet.org/main/dev/runtimecompilescala.html [broken link]

    import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile}
    import scala.reflect.io.{AbstractFile, VirtualDirectory}
    import scala.reflect.runtime
    import scala.reflect.runtime.universe
    import scala.reflect.runtime.universe._
    import scala.tools.nsc.{Global, Settings}
    import scala.collection.mutable
    import java.security.MessageDigest
    import java.math.BigInteger
    
    class Compiler(targetDir: Option[File]) {
    
      val target = targetDir match {
        case Some(dir) => AbstractFile.getDirectory(dir)
        case None => new VirtualDirectory("(memory)", None)
      }
    
      val classCache = mutable.Map[String, Class[_]]()
    
      private val settings = new Settings()
      settings.deprecation.value = true // enable detailed deprecation warnings
      settings.unchecked.value = true // enable detailed unchecked warnings
      settings.outputDirs.setSingleOutput(target)
      settings.usejavacp.value = true
    
      private val global = new Global(settings)
      private lazy val run = new global.Run
    
      val classLoader = new AbstractFileClassLoader(target, this.getClass.getClassLoader)
    
      /**Compiles the code as a class into the class loader of this compiler.
       *
       * @param code
       * @return
       */
      def compile(code: String) = {
        val className = classNameForCode(code)
        findClass(className).getOrElse {
          val sourceFiles = List(new BatchSourceFile("(inline)", wrapCodeInClass(className, code)))
          run.compileSources(sourceFiles)
          findClass(className).get
        }
      }
    
      /** Compiles the source string into the class loader and
       * evaluates it.
       *
       * @param code
       * @tparam T
       * @return
       */
      def eval[T](code: String): T = {
        val cls = compile(code)
        cls.getConstructor().newInstance().asInstanceOf[() => Any].apply().asInstanceOf[T]
      }
    
      def findClass(className: String): Option[Class[_]] = {
        synchronized {
          classCache.get(className).orElse {
            try {
              val cls = classLoader.loadClass(className)
              classCache(className) = cls
              Some(cls)
            } catch {
              case e: ClassNotFoundException => None
            }
          }
        }
      }
    
      protected def classNameForCode(code: String): String = {
        val digest = MessageDigest.getInstance("SHA-1").digest(code.getBytes)
        "sha"+new BigInteger(1, digest).toString(16)
      }
    
      /*
      * Wrap source code in a new class with an apply method.
      */
      private def wrapCodeInClass(className: String, code: String) = {
        "class " + className + " extends (() => Any) {\n" +
          "  def apply() = {\n" +
          code + "\n" +
          "  }\n" +
          "}\n"
      }
    }
    

    0 讨论(0)
提交回复
热议问题