2009-07-31 7 views
3

Après avoir travaillé longtemps en Java, j'ai commencé à m'intéresser à Scala. En tant que projet d'apprentissage, j'essaie de dupliquer une bibliothèque Java qui stocke et récupère des objets d'état de la base de données. Pour cela, je voudrais pouvoir simplement spécifier un objet d'état comme celui-ci:Scala énumération et réflexion

@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 
} 

Le code de sérialisation/non-sérialisation une instance de personne utilise la réflexion pour connaître les types de champs et fonctionne bien pour tout sauf le domaine du genre. Le champ de genre est un Enumeration qui est défini comme:

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

Le problème est que je ne sais pas comment créer je peux utiliser la réflexion aussi une nouvelle valeur de genre en utilisant uniquement la classe Person.

+0

Pourquoi « en utilisant uniquement la classe Person »? – Blaisorblade

Répondre

4

Enumeration de Scala est intéressant, mais les classes de cas ont souvent un avantage sur elle:

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

Ce ont l'avantage d'être match en mesure, et Scala même porter plainte si vous testez un sexe mais pas l'autre . Et, il semble que votre problème se règle plus facilement. :-)

0

Vous pouvez utiliser Gender.Male.id pour obtenir une présentation Int de la valeur du genre masculin. Utilisez Gender.apply() pour le récupérer:

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 

Puisque vous gérez le bit de persistance, tout ce que vous devez faire est de stocker la représentation Int du genre lors de la sérialisation et le restaurer au genre quand désérialisation.

Utilisez une annotation personnalisée dans les champs Enumeration si vous souhaitez généraliser la solution.

0

J'ai rencontré le même problème et trouvé une solution plutôt volumineuse mais cela fonctionne. Vous devez conserver le nom de l'énumération englobante car il n'y a aucun moyen de trouver l'énumération réelle à partir d'une valeur en utilisant la réflexion.

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 

Maintenant, quand vous lisez de la base de données

// 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) 
0

Vérifiez ma EnumReflector:

Vous devez fournir ce type scala du champ.

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) 

Il existe un test unitaire dans le projet qui le démontre.

Aussi, voir mon élargir version de cette réponse ici: Is it possible to use reflection to find the actual type of a field declared to be a Scala Enumeration subtype?