2D matrix implementation - java

Each entity in my game has a Tag object, and there needs to be a way to Add and Remove collisions between Tag's.
This is my code:
public final class CollisionMatrix {
// TODO: Longs have at most 64 bits, so the current implementation fails
// when there are more than 64 tags.
private Map<Integer, Long> matrix = new HashMap<Integer, Long>();
public CollisionMatrix add(Tag tag1, Tag tag2) {
int id1 = tag1.id;
int id2 = tag2.id;
matrix.put(id1, matrix.getOrDefault(id1, 0L) | (1 << id2));
matrix.put(id2, matrix.getOrDefault(id2, 0L) | (1 << id1));
return this;
}
public CollisionMatrix remove(Tag tag1, Tag tag2) {
int id1 = tag1.id;
int id2 = tag2.id;
matrix.put(id1, matrix.getOrDefault(id1, 0L) & ~(1 << id2));
matrix.put(id2, matrix.getOrDefault(id2, 0L) & ~(1 << id1));
return this;
}
public boolean collidesWith(Tag tag1, Tag tag2) {
return 0 != (matrix.getOrDefault(tag1.id, 0L) & (1 << tag2.id));
}
}
This is a very ugly implementation of what I'm trying to achieve. But it working (If the number of tags are no more than 64).
I'm looking for a solution that needs to be efficient and not anti-pattern.

Tag could have a list of tags that indicate collision:
public void add(Tag tag1, Tag tag2) {
tag1.collisions.Add(tag2);
tag2.collisions.Add(tag1);
}
public void remove(Tag tag1, Tag tag2) {
if (collidesWith(tag1,tag2)) {
tag1.collisions.remove(tag2);
tag2.collisions.remove(tag1);
}
}
public boolean collidesWith(Tag tag1, Tag tag2) {
if (tag1.collisions.Contains(tag2) && tag2.collisions.Contains(tag1)) {
return true;
}
return false;
}

I wonder, is it just me or are bitwise operators very illegible? Actually I never used them and haven't really seen them either.
To the topic: What about a simple two-dimensional symmetrical array that stores booleans? array[x][y] represents whether or not x collides with y (those could be IDs of two objects assuming they are not random and start from 0).
Somehow I have a feeling that you're trying too hard to be smart there. I'd never come with an idea to represent an array of booleans as a long and I assume that's what you are trying to there.

Related

Calculating number bonds to value in Java

As part of my application, the database stores "badges" in a user's record in the database. I use the bitwise operator as (as far as I know) no two additions of them can have the same solution. Here are the values:
enum Badge {
SUPPORTER(1),
ALPHA(1 << 1),
BETA_OWNER(1 << 2),
BOOSTER(1 << 3),
ONE_MONTH(1 << 4),
THREE_MONTH(1 << 5),
SIX_MONTH(1 << 6),
ONE_YEAR(1 << 7),
TWO_YEAR(1 << 8),
;
public int value;
public int resolve() {
return value;
}
Badge(int i) {
value = i;
}
}
The method of storing them is as simple as adding up the values of each badge corresponding to the user. However, decoding this value is more tricky.
How would I go about decoding the value from the database into a list of badges that I can manipulate?
Use an EnumSet.The EnumSet can hold each item only once (it's a set). Have a look here for storing values in a database. There are solutions for decoding manually, or you can use Apache Commons for that.
Lets try something like this:
public enum BADGES {SUPPORTER, ALPHA, BETA_OWNER, BOOSTER, ONE_MONTH, THREE_MONTH, SIX_MONTH, ONE_YEAR, TWO_YEAR};
public HashMap<BADGES, Integer> badgesToIntegerMap = /* initialize map where integers are mapped to badges */
public HashMap<Integer, BADGES> integerToBadgesMap = /* initialize map where badges are mapped to their integers */
public List<BADGES> getUserBadges(int userStatus) {
List<BADGES> retVal = new ArrayList<BADGES>();
// Start from highest one, being TWO_YEAR at time of writing
int currentBadge = 1 << 8; //
while (currentBadge > 0) { // These two should be replaced by iterating the badgesToIntegerMap's values
if (userStatus && currentBadge == 1) {
retVal.add(integerToBadgesMap.get(currentBadge));
}
currentBadge = currentBadge >> 1;
}
return retVal;
}
Or you know, just pass these integers into a constructor of each individual badge, and you can avoid one lookup.

Compare String in ENUM

I want to implement storing of enabled or disabled features into database row. When some String value is received from them the network I would like to compare it into ENUM.
ENUM:
public enum TerminalConfigurationFeatureBitString {
Authorize("authorize", 0), // index 0 in bit string
Authorize3d("authorize3d", 1), // index 1 in bit String
Sale("sale", 2), // index 2 in bit String
Sale3d("sale3d", 3), // index 3 in bit String
}
Map<TerminalConfigurationFeatureBitString, Boolean> featureMaps =
config.initFromDatabaseValue(optsFromDatabase);
featureMaps.get(transaction.transactionType);
The best way is to use featureMaps.get(TerminalConfigurationFeatureBitString.Sale);
But I don't know the incoming string what would be.
Now I get warning Unlikely argument type String for get(Object) on a Map<TerminalConfigurationFeatureBitString,Boolean>
Is there any other way to make a query into the ENUM without knowing the key?
In cases like these, I often find myself adding a static method getByX which does a lookup based upon a property of the enum:
public enum BitString {
//...
public static Optional<BitString> getByTransactionType(String transactionType)
{
return Arrays.stream(values())
.filter(x -> x.transactionType.equals(transactionType))
.findFirst();
}
}
Usage:
enum TransactionStatus
{
ENABLED, NOT_ENABLED, NOT_SUPPORTED
}
TransactionStatus status = BitString.getBygetByTransactionType(transaction.transactionType)
.map(bitString -> featureMaps.get(bitString))
.map(enabled -> enabled ? TransactionStatus.ENABLED : TransactionStatus.NOT_ENABLED)
.orElse(TransactionStatus.NOT_SUPPORTED);
Similar to #Michael's answer, you can just generate a static lookup map inside your enum which maps an enums transaction type to the actual enum:
private static final Map<String, TerminalConfigurationFeatureBitString> TRANSACTION_TYPE_TO_ENUM =
Arrays.stream(values()).collect(Collectors.toMap(
TerminalConfigurationFeatureBitString::getTransactionType,
Function.identity()
);
And then have a lookup method, also inside the enum:
public static TerminalConfigurationFeatureBitString getByTransactionType(String transactionType) {
TerminalConfigurationFeatureBitString bitString = TRANSACTION_TYPE_TO_ENUM.get(transactionType);
if(bitString == null) throw new NoSuchElementException(transactionType);
return bitString;
}
This in a way more performant than the mentioned answer, because the Map is created the first time the enum is loaded (So when it is the first time referenced). And thus the iteration happens only once. Also Maps have a rather fast lookup time so you could say that getting an enum this way works O(1) (when ignoring the initial computation time of O(n))
You can extend your enum with extra static method which will try to convert given String on enum item:
enum TerminalConfigurationFeatureBitString {
Authorize("authorize", 0), // index 0 in bit string
Authorize3d("authorize3d", 1), // index 1 in bit String
Sale("sale", 2), // index 2 in bit String
Sale3d("sale3d", 3); // index 3 in bit String
private final String value;
private final int index;
TerminalConfigurationFeatureBitString(String value, int index) {
this.value = value;
this.index = index;
}
public String getValue() {
return value;
}
public int getIndex() {
return index;
}
public static Optional<TerminalConfigurationFeatureBitString> fromValue(String value) {
for (TerminalConfigurationFeatureBitString item : values()) {
if (item.value.equals(value)) {
return Optional.of(item);
}
}
return Optional.empty();
}
}
In case option is not found, return Optional.empty(). If feature is not present it means String representation does not represent any feature. Usage:
public void test() {
EnumMap<TerminalConfigurationFeatureBitString, Boolean> featureMaps = new EnumMap<>(
TerminalConfigurationFeatureBitString.class);
Optional<TerminalConfigurationFeatureBitString> feature = TerminalConfigurationFeatureBitString.fromValue("authorize");
if (!feature.isPresent()) {
System.out.println("Feature is not foudn!");
} else {
Boolean authorize = featureMaps.get(feature.get());
if (authorize != null && authorize) {
System.out.println("Feature is enabled!");
} else {
System.out.println("Feature is disabled!");
}
}
}

Sort Array list of objects based on object attributes

I have list which contains a property class object, In the list i have 3 status
not_paid
paid
part_paid
I want to sort my list below mentioned order.
First - not_paid
second- part_paid
third -paid
How can I sort my list using Comparator class.?
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("not_paid"))) {
return -1;
}
if (p1.equals("not_paid") && p2.equals("not_paid")) {
return -1;
}
return 1;
}
};
This is my Code. i am getting below order using this code.
paid-->not_paid-->part_paid
This is my Update Code. I got my result.
public static Comparator<OrderHistoryItemData> COMPARE_BY_PAYMENT = new Comparator<OrderHistoryItemData>() {
public int compare(OrderHistoryItemData one, OrderHistoryItemData other) {
String p1 = one.getAttributes().getFieldPaymentStatus();
String p2 = other.getAttributes().getFieldPaymentStatus();
if (p1.equals(p2)) {
return 0;
}
if (p1.equals("not_paid") && (p2.equals("part_paid") || p2.equals("paid"))) {
return -1;
}
if (p1.equals("part_paid") && p2.equals("paid")) {
return -1;
}
return 1;
}
};
To avoid complex comparator, I encourage you to export your statuses to an enum. (Plus this will work if you will add more statuses in the future, without the need to change logic in your comparator):
enum PaymentStatus { // Write them in order you want to be sorted
NOT_PAID,
PART_PAID,
PAID
}
Then sorting will be as simple as :
list.sort(Comparator.comparing(item ->item.getAttributes().getFieldPaymentStatus()));
What you can do is first mapping the strings to integers in the desired order, and then simply subtracting them from eachother.
private static Comparator<Payments> comparator = new Comparator<Payments>() {
// Use this mapping function to map the statuses to ints.
// The lowest number comes first
private int map(String str) {
switch (str) {
case "not_paid":
return 0;
case "part_paid":
return 1;
case "paid":
return 2;
default:
return 3;
}
}
// Alternatively, you can use the Map interface to define the sorting
// order.
#Override
public int compare(Payments o1, Payments o2) {
return map(o1.status) - map(o2.status);
}
};
I suggest – Schidu Luca already mentioned it in his answer – that you use enums to define a fixed set of known values, like payment statuses. This provides compile-time safety.
Note: I wouldn't, however, suggest to bind the enum declaration order to the sorting order.

How to get the base pointer of Unicode character?

Currently I have "codePointAt" which returns the code point of the character from the string.
Is there any API or other way to get the base pointer of the current character?
public class Testclass {
public static void main(String[] args) {
String unicodeString = "कागज़";
int currentPoint = unicodeString.codePointAt(0);
// Now currentPoint = 0x0915
// I need currentPoint = 0x0900
}
}
Note# I cannot create the base pointer by addition/subtraction because different language's base point start from different One's/Ten's place values. For e.g.
Armenian - 0530-058F - Base pointer 0x0530(ten's place value)
Devanagari - 0900-097F - Base pointer 0x0900(hundred's place value)
Currently I'm using if-else blocks to get the base pointer which not dynamic and also lengthy approach. :-(
int basePointer;
if(currentPoint>0x600 && currentPoint<=0x6FF)//Means Arabic
{
basePointer = 0x0600;
}
if(currentPoint>0x900 && currentPoint<=0x97F)//Means Devnagri
{
basePointer = 0x0900;
}
OK, after thinking about this for a bit, here is a way to do it just using the Java API. It consists of three parts:
Regenerating the inaccessible block base table blockStarts in Character.UnicodeBlock into a Map
Using Character.UnicodeBlock.of(int) to look up the block name given the codepoint
Using the Map to lookup the Unicode block base given the block name
Note that regenerating the block base table is relatively slow at approx 10-15 ms on my machine, so it would probably be best to generate this once and reuse. I've left the rudimentary timing code in place.
private static final int SUPPLEMENTARY_PRIVATE_USE_AREA_A_BASE = 0x0F0000;
private static final int SUPPLEMENTARY_PRIVATE_USE_AREA_B_BASE = 0x100000;
private static final Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A =
Character.UnicodeBlock.of(SUPPLEMENTARY_PRIVATE_USE_AREA_A_BASE);
private static final Character.UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B =
Character.UnicodeBlock.of(SUPPLEMENTARY_PRIVATE_USE_AREA_B_BASE);
public static Map<Character.UnicodeBlock, Integer> makeUnicodeBlockBaseMap() {
long startNanos = System.nanoTime();
Map<Character.UnicodeBlock, Integer> unicodeBases = new HashMap<>();
// Unicode blocks start on 16 (0x10) byte boundaries.
for (int cp = 0x00000; cp < SUPPLEMENTARY_PRIVATE_USE_AREA_A_BASE; cp += 0x10) {
Character.UnicodeBlock ucb = Character.UnicodeBlock.of(cp);
if (ucb != null) {
unicodeBases.putIfAbsent(ucb, cp);
}
}
// These blocks are huge, so add them manually.
unicodeBases.put(SUPPLEMENTARY_PRIVATE_USE_AREA_A, SUPPLEMENTARY_PRIVATE_USE_AREA_A_BASE);
unicodeBases.put(SUPPLEMENTARY_PRIVATE_USE_AREA_B, SUPPLEMENTARY_PRIVATE_USE_AREA_B_BASE);
long endNanos = System.nanoTime();
System.out.format("Total time = %.3f s%n", (endNanos - startNanos) / 1e9);
return unicodeBases;
}
public static void main(String[] args) {
Map<Character.UnicodeBlock, Integer> unicodeBlockBases = makeUnicodeBlockBaseMap();
String unicodeString = "कागज़";
int currentPoint = unicodeString.codePointAt(0);
Character.UnicodeBlock ucb = Character.UnicodeBlock.of(currentPoint);
System.out.println(ucb); // DEVANAGARI
System.out.format("0x%04X%n", unicodeBlockBases.get(ucb)); // 0x0900
}
You can put the start/end positions to SortedMaps for each language and check the codePoints:
private static final SortedSet<Integer, Integer> startToBase = new TreeMap<>();
private static final SortedSet<Integer, Integer> endToBase = TreeMap<>();
static {
// Fill the SortedMaps:
// latin
startToBase.put(0, 0);
endToBase.put(0x00ff, 0);
// ...
}
// Or load this from a web service, table or anything you find comfortable
public static final int baseCodePoint(int codePoint) {
// The codePoint should be inserted here (after)
int baseFromStart = startToBase.get(startToBase.headMap(codePoint + 1).lastKey());
// the code point should be inserted here (before).
int baseFromEnd = endToBase.get(endToBAse.tailMap(codePoint).firstKey());
if (baseFromStart == baseFromEnd) {
return baseFromStart;
}
throw new IllegalArgumentException(codePoint + " is unknown.");
}
This is what I have done, thanks to Gábor Bakos for inspiration:
TreeMap<Integer, Integer> languageCodePoints = new TreeMap<>();
languageCodePoints.put(0x0020, 0x007E);
languageCodePoints.put(0x00A0, 0x00FF);
languageCodePoints.put(0x0100, 0x017F);
languageCodePoints.put(0x0900, 0x097F); // Devanagri
// So on for all other languages, referred ISO/IEC 10646:2010
// for code points of present languages
In the function I used this only:
String unicodeString = "कागज़";
int currentPoint = unicodeString.codePointAt(0);
int startCodePoint = languageCodePoints.floorKey(currentPoint);
Now "startCodePoint = 0x900" which I really required. I think pretty simple way. :-P
Just one thing is that, I have to maintain "languageCodePoints" TreeMap for new language entries but far better than switch/if-else.
Thanks to all for such kind support. :-)
You can use bit manipulation to find the base pointers, something like this:
switch (codePoint & 0xffffff00) {
case 0x0600: // Arabic
case 0x0900: // Devnagri, though you might need to check it is below 0x97F
case 0x0000: // Latin
default: // Something else
}
Ah, sorry I think Armenian requires further processing, but hopefully the general idea is applicable for most of the languages.
public static int baseCodePoint(int codePoint) {
switch (codePoint & 0xffffff00) {
case 0x0900: if (codePoint < 0x0980) return 0x0900;
case 0x0500: if (codePoint >= 0x0530 && codePoint <= 0x058F) return 0x0530;
// case ...: other bases where it is not the real base
// Handling regular base pointers
default: return codePoint & 0xffffff00;
}
}

Storing EnumSet in a database?

So in C++/C# you can create flags enums to hold multiple values, and storing a single meaningful integer in the database is, of course, trivial.
In Java you have EnumSets, which appear to be quite a nice way to pass enums around in memory, but how do you output the combined EnumSet to an integer for storage? Is there another way to approach this?
Storing the ordinal as a representation of the EnumSet is not a good idea. The ordinal numbers depend on the order of the definition in the Enum class (a related discussion is here). Your database may be easily broken by a refactoring that changes the order of Enum values or introduces new ones in the middle.
You have to introduce a stable representation of individual enum values. These can be int values again and represented in the proposed way for the EnumSet.
Your Enums can implement interfaces so the stable represenation can be directly in the enum value (adapted from Adamski):
interface Stable{
int getStableId();
}
public enum X implements Stable {
A(1), B(2);
private int stableId;
X(int id){
this.stableId = id;
}
#Override public int getStableId() {
return stableId;
}
}
adapted from Adamski's code:
public <E extends Stable> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= (1 << val.getStableId());
}
return ret;
}
Providing your enum fits into an int (i.e. there are <= 32 values) I would roll my own implementation by using each enum's ordinal value; e.g.
public <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
// Bitwise-OR each ordinal value together to encode as single int.
ret |= (1 << val.ordinal());
}
return ret;
}
public <E extends Enum<E>> EnumSet<E> decode(int encoded, Class<E> enumKlazz) {
// First populate a look-up map of ordinal to Enum value.
// This is fairly disgusting: Anyone know of a better approach?
Map<Integer, E> ordinalMap = new HashMap<Integer, E>();
for (E val : EnumSet.allOf(enumKlazz)) {
ordinalMap.put(val.ordinal(), val);
}
EnumSet<E> ret= EnumSet.noneOf(enumKlazz);
int ordinal = 0;
// Now loop over encoded value by analysing each bit independently.
// If the bit is set, determine which ordinal that corresponds to
// (by also maintaining an ordinal counter) and use this to retrieve
// the correct value from the look-up map.
for (int i=1; i!=0; i <<= 1) {
if ((i & encoded) != 0) {
ret.add(ordinalMap.get(ordinal));
}
++ordinal;
}
return ret;
}
Disclaimer: I haven't tested this!
EDIT
As Thomas mentions in the comments the ordinal numbers are unstable in that any change to your enum definition within your code will render the encodings in your database corrupt (e.g. if you insert a new enum value in the middle of your existing definition). My approach to solving this problem is to define an "Enum" table per enumeration, containing a numerical ID (not the ordinal) and the String enum value. When my Java application starts, the first thing the DAO layer does is to read each Enum table into memory and:
Verify that all String enum values in the database match the Java definition.
Initialise a Bi-directional map of ID to enum and vice-versa, which I then use whenever I persist an enum (In other words, all "data" tables reference the database-specific Enum ID, rather than store the String value explicitly).
This is much cleaner / more robust IMHO than the ordinal approach I describe above.
It struck me as a surprise that nobody was suggesting a well-maintained library instead of writing your own. The above answer is spot on and educational but it just encourages people to copy and paste code around (then mostly forget the credits).
Here's my 2 cents:
EnumSet<YourEnum> mySet = EnumSet.of(YourEnum.FIRST);
long vector = EnumUtils.generateBitVector(YourEnum.class, mySet);
EnumSet<YourEnum> sameSet = EnumUtils.processBitVector(YourEnum.class, vector);
See https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/EnumUtils.html
// From Adamski's answer
public static <E extends Enum<E>> int encode(EnumSet<E> set) {
int ret = 0;
for (E val : set) {
ret |= 1 << val.ordinal();
}
return ret;
}
#SuppressWarnings("unchecked")
private static <E extends Enum<E>> EnumSet<E> decode(int code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Integer.numberOfTrailingZeros(code);
code ^= Integer.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}
If you look in the source for RegularEnumSet, which is the implementation for Enum's <= 64 members, you will see that it contains:
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;
elements is a bit-mask where the bit positions equal the enum ordinals, which is exactly what you need. However this attribute is not made availlable through a getter or setter as that would not match the equivalent accessors for the JumboEnumSet.
It is not one of the nicest solutions, but if simplicity and speed is what you are after, you could create 2 static utility methods that retrieve and set the elements attribute using reflection.
For me, I would probably just setup a constants class holding the enum values as integer constants where I can be sure which enum gets assigned what bit.
EnumSet implements Serializable, but there's a lot of overhead if you use that (it is written as an array of IDs, not a BitSet as you might expect, plus the object stream header.)
This is an old post that I found helpful, but with Java 8 or newer I've adapted the solution posted by #finnw into this interface:
public interface BitMaskable {
int getBitMaskOrdinal();
static int bitMaskValue(Set<? extends BitMaskable> set) {
int mask = 0;
for (BitMaskable val : set) {
mask |= (1 << val.getBitMaskOrdinal());
}
return mask;
}
static <E extends Enum<E> & BitMaskable> Set<E> valueOfBitMask(int mask, Class<E> enumType) {
E[] values = enumType.getEnumConstants();
EnumSet<E> result = EnumSet.noneOf(enumType);
Map<Integer, E> ordinalCache = null;
while (mask != 0) {
int ordinal = Integer.numberOfTrailingZeros(mask);
mask ^= Integer.lowestOneBit(mask);
E value = null;
if (ordinalCache != null) {
value = ordinalCache.get(ordinal);
}
if (value == null) {
for (E e : values) {
if (e.getBitMaskOrdinal() == ordinal) {
value = e;
break;
}
// if there are more values to decode and e has a higher
// ordinal than what we've seen, cache that for later
if (mask != 0 && e.getBitMaskOrdinal() > ordinal) {
if (ordinalCache == null) {
ordinalCache = new HashMap<>(values.length);
}
ordinalCache.put(e.getBitMaskOrdinal(), e);
}
}
}
if (value != null) {
result.add(value);
}
}
return result;
}
}
Usage for an enum like this (note the bmOrdinal values are out-of-order from the built-in enum ordinal values):
public enum BitMaskEnum implements BitMaskable {
A(0),
B(2),
C(1),
D(3);
private int bmOrdinal;
private BitMaskEnum(int bmOrdinal) {
this.bmOrdinal = bmOrdinal;
}
#Override
public int getBitMaskOrdinal() {
return bmOrdinal;
}
}
is then along these lines:
// encode as bit mask; result == 5
int result = BitMaskable.bitMaskValue(EnumSet.of(BitMaskEnum.A, BitMaskEnum.B));
// decode into set; result contains A & B
Set<BitMaskEnum> result = BitMaskable.valueOfBitMask(5, BitMaskEnum.class);
With the methods given in the answers it is possible to convert a integer to an EnumSet and vice versa. But I found that this is often error prone. Especially when you get negative values as java only has signed int and long. So if you plan to do such conversions on all sets of enums you might want to use a data structure that already supports this. I have created such a data structure, that can be used just like a BitSet or an EnumSet, but it also has methods such as toLong() and toBitSet(). Note that this requires Java 8 or newer.
Here's the link: http://claude-martin.ch/enumbitset/
Without going into the debate about pros and cons of ordinal values in the database - I posted a possible answer to the given question here:
JPA map collection of Enums
The idea is to create a new PersistentEnumSet which uses the implementation of java.util.RegularEnumSet, but offers the elements bitmask to JPA.
That one can than be used in an embeddable:
#Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
And that set is used in the entity:
#Entity
public class MyEntity {
// ...
#Embedded
private InterestsSet interests = new InterestsSet();
}
For further comments see my answer over there.
I have done some changes on finnw's code, so it works with enumerations having up to 64 items.
// From Adamski's answer
public static <E extends Enum<E>> long encode(EnumSet<E> set) {
long ret = 0;
for (E val : set) {
ret |= 1L << val.ordinal();
}
return ret;
}
#SuppressWarnings("unchecked")
public static <E extends Enum<E>> EnumSet<E> decode(long code,
Class<E> enumType) {
try {
E[] values = (E[]) enumType.getMethod("values").invoke(null);
EnumSet<E> result = EnumSet.noneOf(enumType);
while (code != 0) {
int ordinal = Long.numberOfTrailingZeros(code);
code ^= Long.lowestOneBit(code);
result.add(values[ordinal]);
}
return result;
} catch (IllegalAccessException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
// Probably a NullPointerException, caused by calling this method
// from within E's initializer.
throw (RuntimeException) ex.getCause();
} catch (NoSuchMethodException ex) {
// Shouldn't happen
throw new RuntimeException(ex);
}
}

Categories