Java/Scala反射:按顺序获取类方法并强制对象初始化

fla*_*ian 8 java reflection scala phantom-dsl

我有class一些对象作为内部方法.

我不久前也问了这个问题并得到了一个很好的答案,但这导致了servlet容器中的致命错误.斯卡拉不能持续产生TypeTagURLClassLoader问的一类.

有问题的项目是开源的,可在此处找到.

此处可以找到当前的方法,但它不会保留顺序.对象成员已正确初始化,但是以随机顺序.

问题:如何收集班级成员:

  • 按照它们的定义顺序
  • 以线程安全的方式
  • 用超级类型过滤它们
  • 和贪婪初始化对象(引用module.instance)?

更新:

  • 不要根据这里的链接建议答案,它们已经过测试并且已知失败.
  • 出于风格原因,使用a val代替object不是一种选择.
  • getMethods或者getDeclaredFields知道不保证订单.如果这在某种程度上是可能的,那很可能是Scala反射.

esp*_*nhw 5

来自http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getDeclaredFields():

public Field [] getDeclaredFields()抛出SecurityException

返回Field对象的数组,这些对象反映由此Class对象表示的类或接口声明的所有字段.这包括公共,受保护,默认(包)访问和私有字段,但不包括继承的字段.返回的数组中的元素没有排序,也没有任何特定的顺序.如果类或接口声明没有字段,或者此Class对象表示基本类型,数组类或void,则此方法返回长度为0的数组.请参阅Java语言规范,第8.2和8.3节.

(我的重点).getDeclaredMethods()的文档中明确说明了类似的语言,但getDeclaredClasses()的文档中没有明确的类似语言(但可以认为IMO是隐含的).

所以不,你不能依赖JVM上的Java反射排序; 实际上,我已经看到顺序因运行JVM的体系结构而异(32-与64位).

如果你真的必须以特定的顺序初始化对象(为什么?),你可以使用命名约定并手动排序; 但是,将代码更改为与顺序无关的可能会更好.

更新

您似乎可以从Scala反射API中获取一些内容:

trait EarlyInit {
  val mirror = runtimeMirror(this.getClass.getClassLoader)
  val reflection  = mirror.reflect(this)

  mirror
    .classSymbol(this.getClass)
    .toType
    .members
    .sorted    /// This method is documented to return members "in declaration order"
    .filter(_.isModule)
    .foreach(m => reflection.reflectModule(m.asModule).instance)
  }
}
Run Code Online (Sandbox Code Playgroud)

请参阅API文档:

对此范围中包含的符号进行排序,以便:1)符号以其所有者的线性化顺序显示.2)具有相同所有者的符号以其声明的相同顺序出现.3)合成成员(例如vals/vars的getter/setter)可能以任意顺序出现.

但是,这不能保证一般工作,特别是对于混合Java/Scala项目(因为实际上没有办法按声明顺序获取Java类的成员).另外,请注意Scala运行时反射不是线程安全的,通常不被视为生产就绪.

我仍然觉得通过将设计修改为顺序无关,可能通过不同地编码依赖关系来更好地服务.