tags:

views:

95

answers:

2

Hi, I have an enumeration in scala mapped to strings in JPA. For more comfortable coding, I defined implicit conversions between them. So I now can define value val person.role = "User", - person.role is the enumeration type "User" a String so there's the conversion. But when I try to compare these two, I always get false, because the def equals (arg0: Any) : Boolean takes Any so there's not any conversion triggered. I need some explicit conversion, but my plan was to be able to omit that, what do you think is the best practice | neatest solution here?

+1  A: 

The Value("User") in your Enumeration is of type Val. And I believe it's implementation of equals does not compare the string name of the value. I think one heavy handed way of doing this is creating your own Enumeration and Val so that it returns true if the name match.

But in my code uses, not with JPA, I always convert the string into the MyEnumeration.Value. This is easy with things like:

 object E extends Enumeration { val User = Value("User") }

 scala> val a = E.withName("User")
 a: E.Value = User

Note that when using withName, if the string does not match any name in the enumeration you get an exception.

Then always use the enumeration fields in your comparisons:

scala> a == E.User
res9: Boolean = true

If JPA only returns a string, and there is no way around it. Then I think the best option is to either convert the value to string and match string to string, or upgrade the string to a Val and compare Val. Mixing these types will not work for comparison, unless you you implement some kind of extension to the equals method, and that is tricky.

Thomas
+1  A: 

Expanding on Thomas's answer, if you're using the comparison to branch, using pattern matching may be more appropriate:

object Role extends Enumeration {
   val User = MyValue("User")
   val Admin = MyValue("Admin")

   def MyValue(name: String): Value with Matching = 
         new Val(nextId, name) with Matching

   // enables matching against all Role.Values
   def unapply(s: String): Option[Value] = 
      values.find(s == _.toString)

   trait Matching {
      // enables matching against a particular Role.Value
      def unapply(s: String): Boolean = 
            (s == toString)
   }
}

You can then use this as follows:

def allowAccess(role: String): Boolean = role match {
   case Role.Admin() => true
   case Role.User() => false
   case _ => throw ...
}

or

// str is a String
str match { 
   case Role(role) => // role is a Role.Value
   case Realm(realm) => // realm is a Realm.Value
   ...
}
Aaron Novstrup