所以我在.jar中有一堆编译的case类。我想加载并迭代所有这些,并为每个案例类使用scalavro生成Avro架构。 scalavro AvroType需要一个TypeTag,所以基本上我的问题是如何从jar中的外部case类中适当地反映TypeTags。
import java.net.URL
import com.gensler.scalavro.types.AvroType
import org.clapper.classutil.ClassFinder
import java.io.File
import scala.reflect.internal.util.ScalaClassLoader.URLClassLoader
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{ universe => ru }
object scalaAvroGen extends App {
val jarLocation = "someCaseClasses.jar"
val classpath = List(jarLocation).map(new File(_))
val classLoader = new URLClassLoader(Array[URL](new File(jarLocation).toURI.toURL), this.getClass().getClassLoader())
val finder = ClassFinder(classpath)
val classes = finder.getClasses.filterNot(_.isFinal)
classes.foreach {
loadedClass => {
val typeTag = typeToTypeTag(getType(classLoader.loadClass(loadedClass.name)))
val avroSchema = AvroType.apply(typeTag).schema()
println(avroSchema)
}
}
def getType[T](clazz: Class[T])(implicit runtimeMirror: ru.Mirror) =
runtimeMirror.classSymbol(clazz).toType
def typeToTypeTag[T](tpe: Type): TypeTag[T] = TypeTag.synchronized {
val mirror = scala.reflect.runtime.currentMirror
TypeTag(mirror, new reflect.api.TypeCreator {
def apply[U <: reflect.api.Universe with Singleton](m: reflect.api.Mirror[U]) = {
assert(m eq mirror, s"TypeTag[$tpe] defined in $mirror cannot be migrated to $m.")
tpe.asInstanceOf[U#Type]
}
})
}
}
编译的.jar中的示例case类:
case class SimpleScalaAvroObject(version: Int, name: String)
目前,当我尝试运行此代码时,出现以下错误:
Error:(20, 39) type mismatch; found : reflect.runtime.universe.TypeTag[Nothing] required: reflect.runtime.universe.TypeTag[T] Note: Nothing <: T, but trait TypeTag is invariant in type T. You may wish to investigate a wildcard type such as `_ <: T`. (SLS 3.2.10)
val avroSchema = AvroType.apply(typeTag).schema()
^
现在我确定这不是我唯一的问题,我花了最后两天把所有东西扔到这里。有一次我在SimpleScalaAvroObject上得到了类未找到的异常,所以我可能甚至没有正确反映。
我最终会对我真正关心的案例类进行注释,但现在这只是一个PoC。
请注意,直到几个月前,我还是一个C#dev,对于Scala乱七八糟的混乱感到抱歉。
谢谢!
答案 0 :(得分:2)
您可以使用另一个项目avro4s(免责声明:我写了这个),在编译时而不是运行时生成模式,并且您应该消除任何类型标记问题(因为编译器可以访问更多)有关运行时存在的信息。
使用非常简单,
case class SimpleScalaAvroObject(version: Int, name: String)
// this schema is of type org.apache.avro.Schema
val schema = AvroSchema[SimpleScalaAvroObject]