【问题标题】:scala: serializable alternatives to java.lang.reflect.Fieldscala:java.lang.reflect.Field 的可序列化替代品
【发布时间】:2015-12-07 10:17:06
【问题描述】:

假设User 是一个包含用户信息的案例类:

case class User(name: String, age: Int)

给定一个字段名称(例如"name""age"),我想返回一个提取该字段的函数(无需再次解析字段名称)。简而言之,我需要这个来工作:

val u = User(name = "john",age = 44)
val func = extractFunctionFromFieldName("name") // returns func: User => Any
func(u) // return "john"

阅读反射,我得到了这样的工作:

def extractFunctionFromFieldName(s: String): User => Any = {
  val f = classOf[User].getDeclaredField(s)
  f.setAccessible(true)
  u: User => f.get(u)
}

问题是这个函数是不可序列化的,因为java.lang.reflect.Field 是不可序列化的。

有什么建议或替代方案吗?

笔记/更多背景:

  • 字段列表远远大于{name,age},并且还在不断增长。这就是为什么我要避免硬编码
  • 使用productElement 应该不会出现序列化问题,因为字段已替换为数字。但我了解产品元素的顺序无法保证。
  • 顺便说一句,我需要它是可序列化的,因为我将它与 apache spark 一起使用。

【问题讨论】:

    标签: scala serialization reflection apache-spark case-class


    【解决方案1】:

    使用 productElement 应该不会出现序列化问题,因为字段已替换为数字。但我知道产品元素的顺序无法保证。

    有。对于案例类,它们将与参数的顺序相同。

    或者你可以创建一个类,它仍然可以是一个函数(这里更通用一点;如果不需要,更改为只使用User 应该很容易):

    case class ExtractField[T](s: String)(implicit t: ClassTag[T]) extends (T => Any) {
      @transient lazy val f = {
        val f = t.runtimeClass.getDeclaredField(s)
        f.setAccessible(true)
        f
      }
    
      def apply(x: T) = f.get(x)
    }
    

    这将仅在第一次应用时初始化字段,因此可以在反序列化一次后多次应用,而无需重复 getDeclaredField 调用。

    我最初没有注意到问题已经要求这样做,所以我最初给出的其他解决方案不适用:您可以在函数内移动 f(在您的情况下,f 在您创建函数对象并被它“捕获”,这就是为什么它必须被序列化):

    def extractFunctionFromFieldName(s: String): User => Any = { u: User => 
      val f = classOf[User].getDeclaredField(s)
      f.setAccessible(true)
      f.get(u)
    }
    

    【讨论】:

    • 感谢您的回答。但正如我在问题中所说 - 我希望函数避免每次调用函数时都需要再次解析包含字段名称的字符串。想象一下,函数只生成一次,但应用了十亿次。
    • 这正是我给出最后一个解决方案的原因。它将仅在构造函数中创建f,即在您的反序列化情况下。
    • 您还应该考虑productElement 解决方案,它根本不涉及反射。
    • @Amir 我修复了一些解决方案,现在应该可以正常工作了。
    • 使您的最后一个extractFunctionFromFieldName 可序列化的事实是您将f 标记为瞬态。但出于同样的原因,您在反序列化后无法使用该对象,因为 f 不再具有其价值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 1970-01-01
    • 2011-12-31
    • 2014-12-20
    • 2012-10-09
    相关资源
    最近更新 更多