LANG-1147 EnumUtils *BitVector issue with more than 32 values Enum
This closes #97
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 4d49624..5f54262 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,7 @@
<body>
<release version="3.5" date="tba" description="tba">
+ <action issue="LANG-1147" type="fix" dev="sebb" due-to="Loic Guibert">EnumUtils *BitVector issue with more than 32 values Enum</action>
<action issue="LANG-1059" type="fix" dev="sebb" due-to="Colin Casey">Capitalize javadoc is incorrect</action>
<action issue="LANG-1137" type="add" dev="britter" due-to="Matthew Aguirre">Add check for duplicate event listener in EventListenerSupport</action>
<action issue="LANG-1133" type="bug" dev="chas" due-to="Pascal Schumacher">FastDateParser_TimeZoneStrategyTest#testTimeZoneStrategyPattern fails on Windows with German Locale</action>
diff --git a/src/main/java/org/apache/commons/lang3/EnumUtils.java b/src/main/java/org/apache/commons/lang3/EnumUtils.java
index f985062..699a215 100644
--- a/src/main/java/org/apache/commons/lang3/EnumUtils.java
+++ b/src/main/java/org/apache/commons/lang3/EnumUtils.java
@@ -144,7 +144,7 @@
long total = 0;
for (final E constant : values) {
Validate.isTrue(constant != null, NULL_ELEMENTS_NOT_PERMITTED);
- total |= 1 << constant.ordinal();
+ total |= 1L << constant.ordinal();
}
return total;
}
@@ -175,7 +175,7 @@
}
final long[] result = new long[(enumClass.getEnumConstants().length - 1) / Long.SIZE + 1];
for (final E value : condensed) {
- result[value.ordinal() / Long.SIZE] |= 1 << (value.ordinal() % Long.SIZE);
+ result[value.ordinal() / Long.SIZE] |= 1L << (value.ordinal() % Long.SIZE);
}
ArrayUtils.reverse(result);
return result;
@@ -226,7 +226,7 @@
Collections.addAll(condensed, values);
final long[] result = new long[(enumClass.getEnumConstants().length - 1) / Long.SIZE + 1];
for (final E value : condensed) {
- result[value.ordinal() / Long.SIZE] |= 1 << (value.ordinal() % Long.SIZE);
+ result[value.ordinal() / Long.SIZE] |= 1L << (value.ordinal() % Long.SIZE);
}
ArrayUtils.reverse(result);
return result;
@@ -269,7 +269,7 @@
ArrayUtils.reverse(lvalues);
for (final E constant : enumClass.getEnumConstants()) {
final int block = constant.ordinal() / Long.SIZE;
- if (block < lvalues.length && (lvalues[block] & 1 << (constant.ordinal() % Long.SIZE)) != 0) {
+ if (block < lvalues.length && (lvalues[block] & 1L << (constant.ordinal() % Long.SIZE)) != 0) {
results.add(constant);
}
}
diff --git a/src/test/java/org/apache/commons/lang3/EnumUtilsTest.java b/src/test/java/org/apache/commons/lang3/EnumUtilsTest.java
index a2d0fb0..c2f9c1f 100644
--- a/src/test/java/org/apache/commons/lang3/EnumUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/EnumUtilsTest.java
@@ -215,6 +215,12 @@
assertEquals(5L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.GREEN)));
assertEquals(6L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.AMBER, Traffic.GREEN)));
assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN)));
+
+ // 64 values Enum (to test whether no int<->long jdk convertion issue exists)
+ assertEquals((1L << 31), EnumUtils.generateBitVector(Enum64.class, EnumSet.of(Enum64.A31)));
+ assertEquals((1L << 32), EnumUtils.generateBitVector(Enum64.class, EnumSet.of(Enum64.A32)));
+ assertEquals((1L << 63), EnumUtils.generateBitVector(Enum64.class, EnumSet.of(Enum64.A63)));
+ assertEquals(Long.MIN_VALUE, EnumUtils.generateBitVector(Enum64.class, EnumSet.of(Enum64.A63)));
}
@Test
@@ -227,6 +233,16 @@
assertArrayEquals(EnumUtils.generateBitVectors(Traffic.class, EnumSet.of(Traffic.RED, Traffic.GREEN)), 5L);
assertArrayEquals(EnumUtils.generateBitVectors(Traffic.class, EnumSet.of(Traffic.AMBER, Traffic.GREEN)), 6L);
assertArrayEquals(EnumUtils.generateBitVectors(Traffic.class, EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN)), 7L);
+
+ // 64 values Enum (to test whether no int<->long jdk convertion issue exists)
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, EnumSet.of(Enum64.A31)), (1L << 31));
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, EnumSet.of(Enum64.A32)), (1L << 32));
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, EnumSet.of(Enum64.A63)), (1L << 63));
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, EnumSet.of(Enum64.A63)), Long.MIN_VALUE);
+
+ // More than 64 values Enum
+ assertArrayEquals(EnumUtils.generateBitVectors(TooMany.class, EnumSet.of(TooMany.M2)), 1L, 0L);
+ assertArrayEquals(EnumUtils.generateBitVectors(TooMany.class, EnumSet.of(TooMany.L2, TooMany.M2)), 1L, (1L << 63));
}
@Test
@@ -241,6 +257,12 @@
assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED, Traffic.AMBER, Traffic.GREEN));
//gracefully handles duplicates:
assertEquals(7L, EnumUtils.generateBitVector(Traffic.class, Traffic.RED, Traffic.AMBER, Traffic.GREEN, Traffic.GREEN));
+
+ // 64 values Enum (to test whether no int<->long jdk convertion issue exists)
+ assertEquals((1L << 31), EnumUtils.generateBitVector(Enum64.class, Enum64.A31));
+ assertEquals((1L << 32), EnumUtils.generateBitVector(Enum64.class, Enum64.A32));
+ assertEquals((1L << 63), EnumUtils.generateBitVector(Enum64.class, Enum64.A63));
+ assertEquals(Long.MIN_VALUE, EnumUtils.generateBitVector(Enum64.class, Enum64.A63));
}
@Test
@@ -255,6 +277,17 @@
assertArrayEquals(EnumUtils.generateBitVectors(Traffic.class, Traffic.RED, Traffic.AMBER, Traffic.GREEN), 7L);
//gracefully handles duplicates:
assertArrayEquals(EnumUtils.generateBitVectors(Traffic.class, Traffic.RED, Traffic.AMBER, Traffic.GREEN, Traffic.GREEN), 7L);
+
+ // 64 values Enum (to test whether no int<->long jdk convertion issue exists)
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, Enum64.A31), (1L << 31));
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, Enum64.A32), (1L << 32));
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, Enum64.A63), (1L << 63));
+ assertArrayEquals(EnumUtils.generateBitVectors(Enum64.class, Enum64.A63), Long.MIN_VALUE);
+
+ // More than 64 values Enum
+ assertArrayEquals(EnumUtils.generateBitVectors(TooMany.class, TooMany.M2), 1L, 0L);
+ assertArrayEquals(EnumUtils.generateBitVectors(TooMany.class, TooMany.L2, TooMany.M2), 1L, (1L << 63));
+
}
private void assertArrayEquals(final long[] actual, final long... expected) {
@@ -283,6 +316,12 @@
assertEquals(EnumSet.of(Traffic.RED, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 5L));
assertEquals(EnumSet.of(Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 6L));
assertEquals(EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVector(Traffic.class, 7L));
+
+ // 64 values Enum (to test whether no int<->long jdk convertion issue exists)
+ assertEquals(EnumSet.of(Enum64.A31), EnumUtils.processBitVector(Enum64.class, (1L << 31)));
+ assertEquals(EnumSet.of(Enum64.A32), EnumUtils.processBitVector(Enum64.class, (1L << 32)));
+ assertEquals(EnumSet.of(Enum64.A63), EnumUtils.processBitVector(Enum64.class, (1L << 63)));
+ assertEquals(EnumSet.of(Enum64.A63), EnumUtils.processBitVector(Enum64.class, Long.MIN_VALUE));
}
@Test
@@ -314,6 +353,12 @@
assertEquals(EnumSet.of(Traffic.RED, Traffic.GREEN), EnumUtils.processBitVectors(Traffic.class, 666L, 5L));
assertEquals(EnumSet.of(Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVectors(Traffic.class, 666L, 6L));
assertEquals(EnumSet.of(Traffic.RED, Traffic.AMBER, Traffic.GREEN), EnumUtils.processBitVectors(Traffic.class, 666L, 7L));
+
+ // 64 values Enum (to test whether no int<->long jdk convertion issue exists)
+ assertEquals(EnumSet.of(Enum64.A31), EnumUtils.processBitVectors(Enum64.class, (1L << 31)));
+ assertEquals(EnumSet.of(Enum64.A32), EnumUtils.processBitVectors(Enum64.class, (1L << 32)));
+ assertEquals(EnumSet.of(Enum64.A63), EnumUtils.processBitVectors(Enum64.class, (1L << 63)));
+ assertEquals(EnumSet.of(Enum64.A63), EnumUtils.processBitVectors(Enum64.class, Long.MIN_VALUE));
}
@Test(expected=IllegalArgumentException.class)
@@ -369,6 +414,12 @@
RED, AMBER, GREEN
}
+enum Enum64 {
+ A00, A01, A02, A03, A04, A05, A06, A07, A08, A09, A10, A11, A12, A13, A14, A15,
+ A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31,
+ A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47,
+ A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, A60, A61, A62, A63;
+}
enum TooMany {
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
A1,B1,C1,D1,E1,F1,G1,H1,I1,J1,K1,L1,M1,N1,O1,P1,Q1,R1,S1,T1,U1,V1,W1,X1,Y1,Z1,