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?
views:
95answers:
2The 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.
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
...
}