Scala枚举和反射

时间:2009-07-31 16:01:37

标签: reflection scala enumeration

在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值。

4 个答案:

答案 0 :(得分:4)

Scala的枚举很有意思,但案例类经常比它有优势:

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

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

答案 1 :(得分:0)

您可以使用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。

如果要概括解决方案,请在“枚举”字段中使用自定义注释。

答案 2 :(得分:0)

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

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)

答案 3 :(得分:0)

查看我的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?