1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/test/tools/javac/enum/EnumImplicitPrivateConstructor.java Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,214 @@ 1.4 +/* 1.5 + * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + */ 1.26 + 1.27 +/* 1.28 + * @test 1.29 + * @bug 5009601 5010455 5005748 1.30 + * @summary enum constructors can be declared private 1.31 + * @author Joseph D. Darcy 1.32 + * 1.33 + * @compile -source 1.5 EnumImplicitPrivateConstructor.java 1.34 + * @run main EnumImplicitPrivateConstructor 1.35 + */ 1.36 + 1.37 +import java.util.*; 1.38 +import java.lang.reflect.*; 1.39 +import java.lang.annotation.*; 1.40 + 1.41 +/* 1.42 + * Arguably, only the final and abstract should be held in 1.43 + * ExpectedModifiers; whether or not an enum should be static could be 1.44 + * inferred from getDeclaringClass and working versions of 1.45 + * getEnclosingMethod and getEnclosingConstructor. I.e. if 1.46 + * getDeclaringClass, getEnclosingMethod, and getEnclosingConstructor 1.47 + * were all null, the enum is a top-level class and should not be 1.48 + * static; otherwise, it should be static. 1.49 + */ 1.50 + 1.51 +@ExpectedModifiers(Modifier.FINAL) 1.52 +public enum EnumImplicitPrivateConstructor { 1.53 + RED(255, 0, 0), 1.54 + GREEN(0, 255, 0), 1.55 + BLUE(0, 0, 255); 1.56 + 1.57 + private int r, g, b; 1.58 + EnumImplicitPrivateConstructor(int r, int g, int b) { 1.59 + this.r = r; 1.60 + this.g = g; 1.61 + this.b = b; 1.62 + } 1.63 + 1.64 + /* 1.65 + * Using reflection, Verify that 1.66 + * 1. all non-synthetic constructors of enum classes are marked as private. 1.67 + * 2. top-level enum classes are marked as static 1.68 + * 3. enum's are marked final and abstract as appropriate 1.69 + * 4. enum constructors *cannot* be invoked reflectively 1.70 + */ 1.71 + public static void main(String argv[]) throws Exception { 1.72 + boolean passed = true; 1.73 + 1.74 + Collection<Class> classes = new LinkedHashSet<Class>(); 1.75 + 1.76 + classes.add(Class.forName("EnumImplicitPrivateConstructor")); 1.77 + classes.add(Class.forName("EnumImplicitPrivateConstructor$AnotherEnum")); 1.78 + classes.add(Class.forName("EnumImplicitPrivateConstructor$YetAnotherEnum")); 1.79 + classes.add(Class.forName("EnumImplicitPrivateConstructor$OneMoreEnum")); 1.80 + 1.81 + // Add classes of specialized enum constants 1.82 + for(Enum e: YetAnotherEnum.values()) 1.83 + classes.add(e.getClass()); 1.84 + 1.85 + for(Class clazz: classes) { 1.86 + System.out.println("Testing class " + clazz); 1.87 + 1.88 + int classModifiers = clazz.getModifiers(); 1.89 + 1.90 + // Why is this cast needed? 1.91 + ExpectedModifiers em = (ExpectedModifiers)clazz.getAnnotation(ExpectedModifiers.class); 1.92 + if (em != null) { 1.93 + System.out.println("\tTesting expected modifiers"); 1.94 + int expected = em.value(); 1.95 + 1.96 + if (expected != (classModifiers & (Modifier.ABSTRACT|Modifier.FINAL|Modifier.STATIC))) { 1.97 + passed = false; 1.98 + System.out.println("\tFAILED: Expected 0x" + Integer.toHexString(expected) + 1.99 + " got 0x" +Integer.toHexString(classModifiers)); 1.100 + } 1.101 + } 1.102 + 1.103 + for(Constructor ctor: clazz.getDeclaredConstructors() ) { 1.104 + System.out.println("\tTesting constructor " + ctor); 1.105 + 1.106 + // We don't need no stinkin' access rules 1.107 + try { 1.108 + ctor.setAccessible(true); 1.109 + } catch (java.security.AccessControlException ex) { 1.110 + } 1.111 + 1.112 + int modifiers = ctor.getModifiers(); 1.113 + 1.114 + /* 1.115 + * If clazz is for a specialized enum constant, the 1.116 + * class will have the ENUM bit set but clazz.isEnum() 1.117 + * will be false. A constructor in such a class must 1.118 + * be non-private to allow the parent class to call 1.119 + * the constructor. Therefore, only impose the 1.120 + * private constructor check for genuine isEnum 1.121 + * classes. 1.122 + */ 1.123 + if (clazz.isEnum()) { 1.124 + if ((modifiers & Modifier.PRIVATE) == 0 && 1.125 + ! ctor.isSynthetic() ) { 1.126 + passed = false; 1.127 + System.out.println("\tFAILED: Constructor not marked private: modifiers 0x" + 1.128 + Integer.toHexString(modifiers)); 1.129 + } 1.130 + } 1.131 + 1.132 + try { 1.133 + // Should get exception trying to invoke 1.134 + Object o = null; 1.135 + try { 1.136 + o = ctor.newInstance("abc", 123); 1.137 + } catch (IllegalAccessException ex) { 1.138 + } 1.139 + 1.140 + /* 1.141 + * A better test would query the number (and type) 1.142 + * of parameters and create an appropriate 1.143 + * argument list since IllegalArgumentException can be 1.144 + * thrown for just using the wrong number of arguments. 1.145 + */ 1.146 + 1.147 + if (o != null) { 1.148 + passed = false; 1.149 + System.err.println("Error: Created new enum object!"); 1.150 + System.err.println(o.getClass()); 1.151 + System.err.println(o.toString()); 1.152 + } 1.153 + } catch (IllegalArgumentException iae) {} 1.154 + 1.155 + } 1.156 + } 1.157 + 1.158 + if (!passed) 1.159 + throw new RuntimeException("Error during testing."); 1.160 + } 1.161 + 1.162 + 1.163 + /* 1.164 + * Should be final and not abstract. 1.165 + */ 1.166 + @ExpectedModifiers(Modifier.FINAL|Modifier.STATIC) 1.167 + enum AnotherEnum { 1.168 + YELLOW, 1.169 + CYAN, 1.170 + MAGENTA; 1.171 + } 1.172 + 1.173 + /* 1.174 + * Should be neither final nor abstract. 1.175 + */ 1.176 + @ExpectedModifiers(Modifier.STATIC) 1.177 + enum YetAnotherEnum { 1.178 + GREEN { 1.179 + int value(){ return 1;} 1.180 + }, 1.181 + 1.182 + ORANGE { 1.183 + int value(){ return 2;} 1.184 + }, 1.185 + 1.186 + VIOLET { 1.187 + int value(){ return 3;} 1.188 + }; 1.189 + 1.190 + int value(){ return 0;} 1.191 + } 1.192 + 1.193 + /* 1.194 + * Should be abstract and not final. 1.195 + */ 1.196 + @ExpectedModifiers(Modifier.ABSTRACT|Modifier.STATIC) 1.197 + enum OneMoreEnum { 1.198 + SANGUINE { 1.199 + int value(){ return 1;} 1.200 + }, 1.201 + 1.202 + VERDANT { 1.203 + int value(){ return 2;} 1.204 + }, 1.205 + 1.206 + CERULEAN { 1.207 + int value(){ return 3;} 1.208 + }; 1.209 + 1.210 + abstract int value(); 1.211 + } 1.212 +} 1.213 + 1.214 +@Retention(RetentionPolicy.RUNTIME) 1.215 +@interface ExpectedModifiers { 1.216 + int value(); 1.217 +}