You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2003/11/29 16:03:54 UTC
cvs commit: jakarta-commons/lang/src/test/org/apache/commons/lang/enum NestReferenced.java NestLinked.java NestBroken.java Nest.java EnumTest.java
scolebourne 2003/11/29 07:03:54
Modified: lang/src/java/org/apache/commons/lang/enum Enum.java
lang/src/test/org/apache/commons/lang/enum EnumTest.java
Added: lang/src/test/org/apache/commons/lang/enum
NestReferenced.java NestLinked.java NestBroken.java
Nest.java
Log:
Add description and tests about the perils of nested enums
bug 23374
Revision Changes Path
1.23 +48 -1 jakarta-commons/lang/src/java/org/apache/commons/lang/enum/Enum.java
Index: Enum.java
===================================================================
RCS file: /home/cvs/jakarta-commons/lang/src/java/org/apache/commons/lang/enum/Enum.java,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- Enum.java 7 Sep 2003 14:32:34 -0000 1.22
+++ Enum.java 29 Nov 2003 15:03:54 -0000 1.23
@@ -214,7 +214,54 @@
* </pre>
* <p>The code above will work on JDK 1.2. If JDK1.3 and later is used,
* the subclasses may be defined as anonymous.</p>
+ *
+ * <h4>Nested class Enums</h4>
*
+ * <p>Care must be taken with class loading when defining a static nested class
+ * for enums. The static nested class can be loaded without the surrounding outer
+ * class being loaded. This can result in an empty list/map/iterator being returned.
+ * One solution is to define a static block that references the outer class where
+ * the constants are defined. For example:</p>
+ *
+ * <pre>
+ * public final class Outer {
+ * public static final BWEnum BLACK = new BWEnum("Black");
+ * public static final BWEnum WHITE = new BWEnum("White");
+ *
+ * // static nested enum class
+ * public static final class BWEnum extends Enum {
+ *
+ * static {
+ * // explicitly reference BWEnum class to force constants to load
+ * Object obj = Outer.BLACK;
+ * }
+ *
+ * // ... other methods omitted
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Although the above solves the problem, it is not recommended. The best solution
+ * is to define the constants in the enum class, and hold references in the outer class:
+ *
+ * <pre>
+ * public final class Outer {
+ * public static final BWEnum BLACK = BWEnum.BLACK;
+ * public static final BWEnum WHITE = BWEnum.WHITE;
+ *
+ * // static nested enum class
+ * public static final class BWEnum extends Enum {
+ * // only define constants in enum classes - private if desired
+ * private static final BWEnum BLACK = new BWEnum("Black");
+ * private static final BWEnum WHITE = new BWEnum("White");
+ *
+ * // ... other methods omitted
+ * }
+ * }
+ * </pre>
+ *
+ * <p>For more details, see the 'Nested' test cases.
+ *
* @author Apache Avalon project
* @author Stephen Colebourne
* @author Chris Webb
1.12 +57 -7 jakarta-commons/lang/src/test/org/apache/commons/lang/enum/EnumTest.java
Index: EnumTest.java
===================================================================
RCS file: /home/cvs/jakarta-commons/lang/src/test/org/apache/commons/lang/enum/EnumTest.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- EnumTest.java 18 Aug 2003 02:22:27 -0000 1.11
+++ EnumTest.java 29 Nov 2003 15:03:54 -0000 1.12
@@ -53,6 +53,8 @@
*/
package org.apache.commons.lang.enum;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -132,7 +134,7 @@
}
public void testList() {
- List list = ColorEnum.getEnumList();
+ List list = new ArrayList(ColorEnum.getEnumList());
assertNotNull(list);
@@ -146,19 +148,17 @@
}
public void testMap() {
- Map map = ColorEnum.getEnumMap();
+ Map map = new HashMap(ColorEnum.getEnumMap());
assertNotNull(map);
-
- assertEquals( map.keySet().size(),
- ColorEnum.getEnumList().size());
-
assertTrue(map.containsValue(ColorEnum.RED));
assertTrue(map.containsValue(ColorEnum.GREEN));
assertTrue(map.containsValue(ColorEnum.BLUE));
assertSame(ColorEnum.RED, map.get("Red"));
assertSame(ColorEnum.GREEN, map.get("Green"));
assertSame(ColorEnum.BLUE, map.get("Blue"));
+ assertEquals( map.keySet().size(),
+ ColorEnum.getEnumList().size());
}
public void testGet() {
@@ -413,6 +413,56 @@
assertSame(Extended3Enum.BETA, map.get("Beta"));
assertSame(Extended3Enum.GAMMA, map.get("Gamma"));
assertSame(Extended3Enum.DELTA, map.get("Delta"));
+ }
+
+ //-----------------------------------------------------------------------
+ public void testNested() {
+ List list = new ArrayList(Nest.ColorEnum.getEnumList());
+ assertEquals(3, list.size()); // all is well
+ Iterator it = list.iterator();
+ assertSame(Nest.ColorEnum.RED, it.next());
+ assertSame(Nest.ColorEnum.GREEN, it.next());
+ assertSame(Nest.ColorEnum.BLUE, it.next());
+ // This nesting works because the enum constants are defined in the SAME
+ // class as the getEnumList(). It just acts as a normal enum.
+ }
+
+ public void testNestedBroken() {
+ List list = new ArrayList(NestBroken.ColorEnum.getEnumList());
+ assertEquals(0, list.size()); // no enums!!!
+ // this is BROKEN because the enum constants are defined in a DIFFERENT
+ // class from getEnumList(). Once NestBroken class is referenced,
+ // and thus class loaded with its enum constants, the getEnumList works:
+ new NestBroken();
+ list = new ArrayList(NestBroken.ColorEnum.getEnumList());
+ assertEquals(3, list.size()); // all is well!!!
+ Iterator it = list.iterator();
+ assertSame(NestBroken.RED, it.next());
+ assertSame(NestBroken.GREEN, it.next());
+ assertSame(NestBroken.BLUE, it.next());
+ }
+
+ public void testNestedLinked() {
+ List list = new ArrayList(NestLinked.ColorEnum.getEnumList());
+ assertEquals(3, list.size()); // all is well
+ Iterator it = list.iterator();
+ assertSame(NestLinked.RED, it.next());
+ assertSame(NestLinked.GREEN, it.next());
+ assertSame(NestLinked.BLUE, it.next());
+ // This nesting works because a static block in the enum class forces a
+ // class load of the outer class which defines the enum constants.
+ }
+
+ public void testNestedReferenced() {
+ List list = new ArrayList(NestReferenced.ColorEnum.getEnumList());
+ assertEquals(3, list.size()); // all is well
+ Iterator it = list.iterator();
+ assertSame(NestReferenced.RED, it.next());
+ assertSame(NestReferenced.GREEN, it.next());
+ assertSame(NestReferenced.BLUE, it.next());
+ // This nesting works because the enum constants are actually defined in
+ // the SAME class as the getEnumList(). The references in the outer class
+ // are just extra references.
}
}
1.1 jakarta-commons/lang/src/test/org/apache/commons/lang/enum/NestReferenced.java
Index: NestReferenced.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.commons.lang.enum;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Color enumeration which demonstrates how to provide a view of the constants
* in a different class to the Enum. This technique is the safest, however it
* is obviously inconvenient as it involves defining two sets of constants.
* See NestedLinked for an alternative.
*
* @author Stephen Colebourne
* @version $Id: NestReferenced.java,v 1.1 2003/11/29 15:03:54 scolebourne Exp $
*/
public final class NestReferenced {
public static final ColorEnum RED = ColorEnum.RED;
public static final ColorEnum GREEN = ColorEnum.GREEN;
public static final ColorEnum BLUE = ColorEnum.BLUE;
public NestReferenced() {
super();
}
public static final class ColorEnum extends Enum {
// must be defined here, not just in outer class
private static final ColorEnum RED = new ColorEnum("Red");
private static final ColorEnum GREEN = new ColorEnum("Green");
private static final ColorEnum BLUE = new ColorEnum("Blue");
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
}
1.1 jakarta-commons/lang/src/test/org/apache/commons/lang/enum/NestLinked.java
Index: NestLinked.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.commons.lang.enum;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Color enumeration which demonstrates how to define the constants in a
* different class to the Enum. The extra <code>static{}</code> block is
* needed to ensure that the enum constants are created before the
* static methods on the ColorEnum are used.
* <p>
* The class loader sees the two classes here as independent - the enum
* class is nested, not an inner class. The static block thus forces the
* class load of the outer class, which is needed to initialise the enums.
*
* @author Stephen Colebourne
* @version $Id: NestLinked.java,v 1.1 2003/11/29 15:03:54 scolebourne Exp $
*/
public final class NestLinked {
public static final ColorEnum RED = new ColorEnum("Red");
public static final ColorEnum GREEN = new ColorEnum("Green");
public static final ColorEnum BLUE = new ColorEnum("Blue");
public NestLinked() {
super();
}
public static final class ColorEnum extends Enum {
static {
// Explicitly reference the class where the enums are defined
Object obj = NestLinked.RED;
}
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
}
1.1 jakarta-commons/lang/src/test/org/apache/commons/lang/enum/NestBroken.java
Index: NestBroken.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.commons.lang.enum;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Color enumeration which demonstrates how to break the enum system.
* <p>
* The class loader sees the two classes here as independent - the enum
* class is nested, not an inner class. Calling getEnumList() on ColorEnum
* will return an empty list, unless and until the NestBroken class is
* referenced.
*
* @author Stephen Colebourne
* @version $Id: NestBroken.java,v 1.1 2003/11/29 15:03:54 scolebourne Exp $
*/
public final class NestBroken {
public static final ColorEnum RED = new ColorEnum("Red");
public static final ColorEnum GREEN = new ColorEnum("Green");
public static final ColorEnum BLUE = new ColorEnum("Blue");
public NestBroken() {
super();
}
public static final class ColorEnum extends Enum {
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
}
1.1 jakarta-commons/lang/src/test/org/apache/commons/lang/enum/Nest.java
Index: Nest.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowledgement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgement may appear in the software itself,
* if and wherever such third-party acknowledgements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.commons.lang.enum;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Color enumeration demonstrating a normal simple nesting case.
* All is well here as the nested enum class is really no different
* to any other class.
*
* @author Stephen Colebourne
* @version $Id: Nest.java,v 1.1 2003/11/29 15:03:54 scolebourne Exp $
*/
public final class Nest {
public Nest() {
super();
}
public static final class ColorEnum extends Enum {
public static final ColorEnum RED = new ColorEnum("Red");
public static final ColorEnum GREEN = new ColorEnum("Green");
public static final ColorEnum BLUE = new ColorEnum("Blue");
private ColorEnum(String color) {
super(color);
}
public static ColorEnum getEnum(String color) {
return (ColorEnum) getEnum(ColorEnum.class, color);
}
public static Map getEnumMap() {
return getEnumMap(ColorEnum.class);
}
public static List getEnumList() {
return getEnumList(ColorEnum.class);
}
public static Iterator iterator() {
return iterator(ColorEnum.class);
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org