Scala宏:检查Java字段是否标记为瞬态
如何使用
Scala宏检查
Java类字段上的ACC_TRANSIENT标志?
TermSymbol有像isPrivate和amp; isProtected但没有任何类型的isTransient方法. 检查Scala的瞬态 对于Scala类,使用@transient注释生成带有ACC_TRANSIENT标志的字段: class ScalaExample { @transient protected var ignoredField: String = null } 在类文件中,您最终得到: private transient java.lang.String ignoredField; descriptor: Ljava/lang/String; flags: ACC_PRIVATE,ACC_TRANSIENT 然后在宏中我可以看到@transient注释: scala> typeOf[ScalaExample].member(TermName("ignoredField")).asTerm.accessed.annotations res0: List[universe.Annotation] = List(scala.transient) 检查瞬态是否为Java? 但是,如果我有一个Java类: public class JavaExample { protected transient String ignoredField; } 哪个产生类似的字节码(该字段受保护而不是私有): protected transient java.lang.String ignoredField; descriptor: Ljava/lang/String; flags: ACC_PROTECTED,ACC_TRANSIENT 没有注释: scala> typeOf[JavaExample].member(TermName("ignoredField")).asTerm.accessed.annotations java.lang.AssertionError: assertion failed: variable ignoredField at scala.reflect.internal.Symbols$Symbol.accessed(Symbols.scala:1978) at scala.reflect.internal.Symbols$Symbol.accessed(Symbols.scala:1974) at scala.reflect.internal.Symbols$TermSymbol.accessed(Symbols.scala:2658) ... 43 elided scala> typeOf[JavaExample].member(TermName("ignoredField")).asTerm.annotations res2: List[universe.Annotation] = List() 我意识到,对于Scala类,@ transnsient注释可能正在从ScalaSignature中读取而不是ACC_TRANSIENT标志,这就是为什么它不会出现在java类中的原因. 可能的解决方法/黑客 使用Scala运行时反射我可以获取JavaExample的java.lang.Class,然后使用Java反射使用java.lang.reflect.Modifier.isTransient(…)检查ACC_TRANSIENT标志.但对于使用编译时间反射的宏来说,这似乎并不理想.我还没有弄清楚如何让它在宏中工作,所以我不确定它是否可能. 解决方法
可能的解决方法/黑客解决方案
我最终实现了问题中提到的可能的解决方法/ Hack: import java.lang.reflect.Modifier import java.net.URLClassLoader import scala.reflect.macros._ abstract class MacroHelpers { self => val ctx: Context import ctx.universe._ private lazy val classLoader: ClassLoader = new URLClassLoader(ctx.classPath.toArray) def isJavaTransient(sym: Symbol): Boolean = { if (!sym.isJava || !sym.isTerm || !sym.asTerm.isVar) return false val className: String = sym.owner.asClass.fullName val clazz: Class[_] = classLoader.loadClass(className) Modifier.isTransient(clazz.getDeclaredField(sym.name.decoded).getModifiers()) } } 这似乎对我使用Scala 2.10.4和2.11.1都很好.如果您在混合的Scala / Java项目中使用宏并且正在尝试检查项目中的Java类,那么我认为您需要在build.sbt中使用CompileOrder.JavaThenScala以确保Java类出现在类路径之前宏运行: compileOrder := CompileOrder.JavaThenScala (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |