【问题标题】:Scala enumeration and reflectionScala 枚举和反射
【发布时间】:2009-07-31 16:01:37
【问题描述】:

在 Java 工作了很长时间后,我开始对 Scala 产生了兴趣。 作为一个学习项目,我正在尝试复制一个 java 库来存储和检索数据库中的状态对象。 为此,我希望能够像这样指定一个状态对象:

@PersistName("PERSON") case class  Person extends Entity {
  @Persist var id:Long = -1
  @Persist @MaxLength(80) var firstName = ""
  @Persist @MaxLength(80) var lastName = ""
  @Persist var gender = Gender.Male
  @Persist @MaxLength(80) var userName  = ""
  @Persist @OptionClass(classOf[Date]) var birthDay:Option[Date] = None
}

序列化/反序列化 Person 实例的代码使用反射来了解字段的类型,并且对除了性别字段之外的所有字段都可以正常工作。 性别字段是一个枚举,定义为:

object Gender extends Enumeration {
  type Gender = Value
  val Male,Female,Unknown = Value
}

问题是我不知道如何使用反射也只使用 Person 类来创建新的 Gender 值。

【问题讨论】:

  • 为什么“只使用 Person 类”?

标签: reflection scala enumeration


【解决方案1】:

Scala 的 Enumeration 很有趣,但案例类通常比它更有优势:

sealed class Gender
case object Male extends Gender
case object Female extends Gender

这具有matchable 的优势,如果您测试一种性别而不是另一种性别,Scala 甚至会抱怨。而且,它似乎更容易解决您的问题。 :-)

【讨论】:

    【解决方案2】:

    您可以使用 Gender.Male.id 来获取男性性别值的 Int 表示。使用 Gender.apply() 将其取回:

    val person = Person()
    
    println("gender = " + person.gender.id)
    // prints "gender = 0" on my mac
    
    person.gender = Gender(Gender.Female.id) // have a little operation
    println("gender = " + person.gender.id)
    // prints "gender = 1" on my mac
    

    由于您正在处理持久性位,您需要做的就是在序列化时存储性别的 Int 表示,并在反序列化时将其恢复为 Gender。

    如果您想概括解决方案,请在枚举字段上使用自定义注释。

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,并找到了一个相当庞大的解决方案,但它确实有效。您需要保留封闭枚举的名称,因为无法使用反射从值中找出真正的枚举。

      object WeekDay extends Enumeration {
        type WeekDay = Value
        val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
      }
      
      val day = WeekDay.Fri
      
      val className = day.getClass.getField("$outer").get(day).getClass.getCanonicalName
      
      // write to database
      // className // String
      // day.id  // Int
      

      现在当你从数据库中读出时

      // read from database
      // obtain className and id
      
      // enumObject will be WeekDay
      val enumObject = Class.forName(className).getField("MODULE$").get().asInstanceOf[Enumeration]
      
      // value will be WeekDay.Fri
      val value = enumObject(id)
      

      【讨论】:

        【解决方案4】:

        查看我的EnumReflector

        您需要为其提供字段的 scala 类型。

        val enumObject:Type = ... object's scala.Enumeration field
        val typ:Type = ... object's scala.Enumeration field's scala type
        
        val isEnum = EnumReflector.isEnumeration(typ)
        
        val reflector = EnumReflector(typ)
        val eid = reflector.toID(enumObject)
        val enum = reflector.fromID(eid)
        assertTrue(eid eq enum)
        

        项目中有一个单元测试来演示它。

        另外,请在此处查看此答案的扩展版本:Is it possible to use reflection to find the actual type of a field declared to be a Scala Enumeration subtype?

        【讨论】:

          猜你喜欢
          • 2017-11-07
          • 1970-01-01
          • 2016-07-13
          • 2012-03-18
          • 1970-01-01
          • 1970-01-01
          • 2011-06-12
          • 2016-03-23
          • 1970-01-01
          相关资源
          最近更新 更多