Reflection Scala枚举和反射

Reflection Scala枚举和反射,reflection,scala,enumeration,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

在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类创建新的性别值。

Scala的枚举很有趣,但case类通常比它有优势:

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

这样做的好处是
match
able,如果你测试的是一种性别,而不是另一种性别,Scala甚至会抱怨。而且,它似乎更容易解决您的问题。:-)

可以使用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
因为您正在处理持久性位,所以您所需要做的就是在序列化时存储gender的Int表示,并在反序列化时将其恢复为gender


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

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

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

您需要为其提供字段的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)
项目中有一个单元测试来演示它

另外,请参见我在此处对此答案的展开版本:

为什么“仅使用Person类”?