Storing EnumSet in a database?

前端 未结 10 1716
借酒劲吻你
借酒劲吻你 2020-12-03 21:24

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 Enu

相关标签:
10条回答
  • 2020-12-03 21:46

    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

    0 讨论(0)
  • 2020-12-03 21:49

    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.

    0 讨论(0)
  • 2020-12-03 21:51

    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.)

    0 讨论(0)
  • 2020-12-03 21:54
    // 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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题