duke@1: /* ohair@554: * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. duke@1: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@1: * duke@1: * This code is free software; you can redistribute it and/or modify it duke@1: * under the terms of the GNU General Public License version 2 only, as duke@1: * published by the Free Software Foundation. duke@1: * duke@1: * This code is distributed in the hope that it will be useful, but WITHOUT duke@1: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@1: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@1: * version 2 for more details (a copy is included in the LICENSE file that duke@1: * accompanied this code). duke@1: * duke@1: * You should have received a copy of the GNU General Public License version duke@1: * 2 along with this work; if not, write to the Free Software Foundation, duke@1: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@1: * ohair@554: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@554: * or visit www.oracle.com if you need additional information or have any ohair@554: * questions. duke@1: */ duke@1: duke@1: /* duke@1: * @test duke@1: * @bug 5009601 5010455 5005748 duke@1: * @summary enum constructors can be declared private duke@1: * @author Joseph D. Darcy duke@1: */ duke@1: duke@1: import java.util.*; duke@1: import java.lang.reflect.*; duke@1: import java.lang.annotation.*; duke@1: duke@1: /* duke@1: * Arguably, only the final and abstract should be held in duke@1: * ExpectedModifiers; whether or not an enum should be static could be duke@1: * inferred from getDeclaringClass and working versions of duke@1: * getEnclosingMethod and getEnclosingConstructor. I.e. if duke@1: * getDeclaringClass, getEnclosingMethod, and getEnclosingConstructor duke@1: * were all null, the enum is a top-level class and should not be duke@1: * static; otherwise, it should be static. duke@1: */ duke@1: duke@1: @ExpectedModifiers(Modifier.FINAL) duke@1: public enum EnumImplicitPrivateConstructor { duke@1: RED(255, 0, 0), duke@1: GREEN(0, 255, 0), duke@1: BLUE(0, 0, 255); duke@1: duke@1: private int r, g, b; duke@1: EnumImplicitPrivateConstructor(int r, int g, int b) { duke@1: this.r = r; duke@1: this.g = g; duke@1: this.b = b; duke@1: } duke@1: duke@1: /* duke@1: * Using reflection, Verify that duke@1: * 1. all non-synthetic constructors of enum classes are marked as private. duke@1: * 2. top-level enum classes are marked as static duke@1: * 3. enum's are marked final and abstract as appropriate duke@1: * 4. enum constructors *cannot* be invoked reflectively duke@1: */ duke@1: public static void main(String argv[]) throws Exception { duke@1: boolean passed = true; duke@1: duke@1: Collection classes = new LinkedHashSet(); duke@1: duke@1: classes.add(Class.forName("EnumImplicitPrivateConstructor")); duke@1: classes.add(Class.forName("EnumImplicitPrivateConstructor$AnotherEnum")); duke@1: classes.add(Class.forName("EnumImplicitPrivateConstructor$YetAnotherEnum")); duke@1: classes.add(Class.forName("EnumImplicitPrivateConstructor$OneMoreEnum")); duke@1: duke@1: // Add classes of specialized enum constants duke@1: for(Enum e: YetAnotherEnum.values()) duke@1: classes.add(e.getClass()); duke@1: duke@1: for(Class clazz: classes) { duke@1: System.out.println("Testing class " + clazz); duke@1: duke@1: int classModifiers = clazz.getModifiers(); duke@1: duke@1: // Why is this cast needed? duke@1: ExpectedModifiers em = (ExpectedModifiers)clazz.getAnnotation(ExpectedModifiers.class); duke@1: if (em != null) { duke@1: System.out.println("\tTesting expected modifiers"); duke@1: int expected = em.value(); duke@1: duke@1: if (expected != (classModifiers & (Modifier.ABSTRACT|Modifier.FINAL|Modifier.STATIC))) { duke@1: passed = false; duke@1: System.out.println("\tFAILED: Expected 0x" + Integer.toHexString(expected) + duke@1: " got 0x" +Integer.toHexString(classModifiers)); duke@1: } duke@1: } duke@1: duke@1: for(Constructor ctor: clazz.getDeclaredConstructors() ) { duke@1: System.out.println("\tTesting constructor " + ctor); duke@1: duke@1: // We don't need no stinkin' access rules duke@1: try { duke@1: ctor.setAccessible(true); duke@1: } catch (java.security.AccessControlException ex) { duke@1: } duke@1: duke@1: int modifiers = ctor.getModifiers(); duke@1: duke@1: /* duke@1: * If clazz is for a specialized enum constant, the duke@1: * class will have the ENUM bit set but clazz.isEnum() duke@1: * will be false. A constructor in such a class must duke@1: * be non-private to allow the parent class to call duke@1: * the constructor. Therefore, only impose the duke@1: * private constructor check for genuine isEnum duke@1: * classes. duke@1: */ duke@1: if (clazz.isEnum()) { duke@1: if ((modifiers & Modifier.PRIVATE) == 0 && duke@1: ! ctor.isSynthetic() ) { duke@1: passed = false; duke@1: System.out.println("\tFAILED: Constructor not marked private: modifiers 0x" + duke@1: Integer.toHexString(modifiers)); duke@1: } duke@1: } duke@1: duke@1: try { duke@1: // Should get exception trying to invoke duke@1: Object o = null; duke@1: try { duke@1: o = ctor.newInstance("abc", 123); duke@1: } catch (IllegalAccessException ex) { duke@1: } duke@1: duke@1: /* duke@1: * A better test would query the number (and type) duke@1: * of parameters and create an appropriate duke@1: * argument list since IllegalArgumentException can be duke@1: * thrown for just using the wrong number of arguments. duke@1: */ duke@1: duke@1: if (o != null) { duke@1: passed = false; duke@1: System.err.println("Error: Created new enum object!"); duke@1: System.err.println(o.getClass()); duke@1: System.err.println(o.toString()); duke@1: } duke@1: } catch (IllegalArgumentException iae) {} duke@1: duke@1: } duke@1: } duke@1: duke@1: if (!passed) duke@1: throw new RuntimeException("Error during testing."); duke@1: } duke@1: duke@1: duke@1: /* duke@1: * Should be final and not abstract. duke@1: */ duke@1: @ExpectedModifiers(Modifier.FINAL|Modifier.STATIC) duke@1: enum AnotherEnum { duke@1: YELLOW, duke@1: CYAN, duke@1: MAGENTA; duke@1: } duke@1: duke@1: /* duke@1: * Should be neither final nor abstract. duke@1: */ duke@1: @ExpectedModifiers(Modifier.STATIC) duke@1: enum YetAnotherEnum { duke@1: GREEN { duke@1: int value(){ return 1;} duke@1: }, duke@1: duke@1: ORANGE { duke@1: int value(){ return 2;} duke@1: }, duke@1: duke@1: VIOLET { duke@1: int value(){ return 3;} duke@1: }; duke@1: duke@1: int value(){ return 0;} duke@1: } duke@1: duke@1: /* duke@1: * Should be abstract and not final. duke@1: */ duke@1: @ExpectedModifiers(Modifier.ABSTRACT|Modifier.STATIC) duke@1: enum OneMoreEnum { duke@1: SANGUINE { duke@1: int value(){ return 1;} duke@1: }, duke@1: duke@1: VERDANT { duke@1: int value(){ return 2;} duke@1: }, duke@1: duke@1: CERULEAN { duke@1: int value(){ return 3;} duke@1: }; duke@1: duke@1: abstract int value(); duke@1: } duke@1: } duke@1: duke@1: @Retention(RetentionPolicy.RUNTIME) duke@1: @interface ExpectedModifiers { duke@1: int value(); duke@1: }