I found a simple way to map an EnumSet directly to a bitMask/long value in DB :
When you do
Code:
message.setAllowedEnumSet(EnumSet.of(MyEnum.A,MyEnum.B,MyEnum.D));
In dB you end up with LongVal=11 (bitMask for MyEnum.A,MyEnum.B,MyEnum.D )
Here is the mapping :
* The allowedEnumSet field is transient because in fact it's mapped by the allowedBitMask long.
* It makes use of the hibernate annotation @AccessType("property") so hibernate uses the getters/setters for the allowedBitMask field.
* getAllowedBitMask and setAllowedBitMask methods are protected, so they do not pollute your domain model, they are just used by hibernate.
Code:
@Transient
EnumSet<MyEnum> allowedEnumSet ;
@Column(name = "allowed")
@AccessType("property")
private long allowedBitMask;
protected long getAllowedBitMask(){
return EnumHack.getElements(allowedEnumSet);
}
protected void setAllowedBitMask(long l){
if (allowedEnumSet==null){
allowedEnumSet= EnumSet.noneOf(MyEnum.class);
}
EnumHack.setElements(allowedEnumSet,l);
}
And here is the EnumHack utility Class, making use of reflection to access the bitMask value inside of the EnumSet implementation.
This hack is necessary because java.util.RegularEnumSet is package protected and the elements Field is normally not accessible.
Code:
public class EnumHack {
public static Long getElements(EnumSet enumSet) {
// can't even use insanceOf, the class is package protected
if ("RegularEnumSet".equals(enumSet.getClass().getSimpleName())) {
try {
Field elementsField = enumSet.getClass().getDeclaredField("elements");
elementsField.setAccessible(true);
return elementsField.getLong(enumSet);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
throw new UnsupportedOperationException("JumboEnumSet is not supported for now");
}
}
public static void setElements(EnumSet enumSet,long l) {
// can't even use insanceOf, the class is package protected
if ("RegularEnumSet".equals(enumSet.getClass().getSimpleName())) {
try {
Field elementsField = enumSet.getClass().getDeclaredField("elements");
elementsField.setAccessible(true);
elementsField.setLong(enumSet,l);
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
throw new UnsupportedOperationException("JumboEnumSet is not supported for now");
}
}
}
Of course this is a quick hack, not ready for production use ;)