如何查看 ACC_TRANSIENT 使用 Scala 宏在 Java 类的字段上标记?
术语符号 具有 isPrivate 和 isProtected 之类的方法,但没有任何类型的 isTransient 方法。
检查 Scala 的 transient
对于 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的 transient ?
但是,如果我有一个 Java 类:
public class JavaExample {
protected transient String ignoredField;
}
这会产生类似的字节码(该字段是 protected 而不是私有(private)的):
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 类, @ transient 注释可能是从 ScalaSignature 而不是 中读取的。 ACC_TRANSIENT 标志,这就是为什么它不会出现在 java 类中。
可能的解决方法/黑客
使用 Scala 运行时反射,我可以获得 JavaExample 的 java.lang.Class,然后使用 Java 反射检查 ACC_TRANSIENT 使用 java.lang.reflect.Modifier.isTransient(...) 标记。但这对于使用编译时反射的宏来说似乎并不理想。我还没有弄清楚如何让它在宏中工作,所以我不确定它是否可能。
最佳答案
可能的解决方法/黑客解决方案
我最终实现了问题中提到的可能的解决方法/黑客:
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 类,那么我认为您需要
CompileOrder.JavaThenScala
在您的 build.sbt 中确保 Java 类在宏运行之前出现在类路径中:compileOrder := CompileOrder.JavaThenScala
关于Scala 宏 : Checking if a Java Field is marked as transient,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24125409/