EnumImplicitPrivateConstructor.java revision 288:84061bd68019
1/*
2 * Copyright 2004 Sun Microsystems, Inc.  All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 5009601 5010455 5005748
27 * @summary enum constructors can be declared private
28 * @author Joseph D. Darcy
29 */
30
31import java.util.*;
32import java.lang.reflect.*;
33import java.lang.annotation.*;
34
35/*
36 * Arguably, only the final and abstract should be held in
37 * ExpectedModifiers; whether or not an enum should be static could be
38 * inferred from getDeclaringClass and working versions of
39 * getEnclosingMethod and getEnclosingConstructor.  I.e. if
40 * getDeclaringClass, getEnclosingMethod, and getEnclosingConstructor
41 * were all null, the enum is a top-level class and should not be
42 * static; otherwise, it should be static.
43 */
44
45@ExpectedModifiers(Modifier.FINAL)
46public enum EnumImplicitPrivateConstructor {
47    RED(255, 0, 0),
48    GREEN(0, 255, 0),
49    BLUE(0, 0, 255);
50
51    private int r, g, b;
52    EnumImplicitPrivateConstructor(int r, int g, int b) {
53        this.r = r;
54        this.g = g;
55        this.b = b;
56    }
57
58    /*
59     * Using reflection, Verify that
60     * 1. all non-synthetic constructors of enum classes are marked as private.
61     * 2. top-level enum classes are marked as static
62     * 3. enum's are marked final and abstract as appropriate
63     * 4. enum constructors *cannot* be invoked reflectively
64     */
65    public static void main(String argv[]) throws Exception {
66        boolean passed = true;
67
68        Collection<Class> classes = new LinkedHashSet<Class>();
69
70        classes.add(Class.forName("EnumImplicitPrivateConstructor"));
71        classes.add(Class.forName("EnumImplicitPrivateConstructor$AnotherEnum"));
72        classes.add(Class.forName("EnumImplicitPrivateConstructor$YetAnotherEnum"));
73        classes.add(Class.forName("EnumImplicitPrivateConstructor$OneMoreEnum"));
74
75        // Add classes of specialized enum constants
76        for(Enum e: YetAnotherEnum.values())
77            classes.add(e.getClass());
78
79        for(Class clazz: classes) {
80            System.out.println("Testing class " + clazz);
81
82            int classModifiers = clazz.getModifiers();
83
84            // Why is this cast needed?
85            ExpectedModifiers em = (ExpectedModifiers)clazz.getAnnotation(ExpectedModifiers.class);
86            if (em != null) {
87                System.out.println("\tTesting expected modifiers");
88                int expected = em.value();
89
90                if (expected != (classModifiers & (Modifier.ABSTRACT|Modifier.FINAL|Modifier.STATIC))) {
91                    passed = false;
92                    System.out.println("\tFAILED: Expected 0x" + Integer.toHexString(expected) +
93                                       " got 0x" +Integer.toHexString(classModifiers));
94                }
95            }
96
97            for(Constructor ctor: clazz.getDeclaredConstructors() ) {
98                System.out.println("\tTesting constructor " + ctor);
99
100                // We don't need no stinkin' access rules
101                try {
102                    ctor.setAccessible(true);
103                } catch (java.security.AccessControlException ex) {
104                }
105
106                int modifiers = ctor.getModifiers();
107
108                /*
109                 * If clazz is for a specialized enum constant, the
110                 * class will have the ENUM bit set but clazz.isEnum()
111                 * will be false.  A constructor in such a class must
112                 * be non-private to allow the parent class to call
113                 * the constructor.  Therefore, only impose the
114                 * private constructor check for genuine isEnum
115                 * classes.
116                 */
117                if (clazz.isEnum()) {
118                    if ((modifiers & Modifier.PRIVATE) == 0 &&
119                        ! ctor.isSynthetic() ) {
120                        passed = false;
121                        System.out.println("\tFAILED: Constructor not marked private: modifiers 0x" +
122                                           Integer.toHexString(modifiers));
123                    }
124                }
125
126                try {
127                    // Should get exception trying to invoke
128                    Object o = null;
129                    try {
130                        o = ctor.newInstance("abc", 123);
131                    } catch (IllegalAccessException ex) {
132                    }
133
134                    /*
135                     * A better test would query the number (and type)
136                     * of parameters and create an appropriate
137                     * argument list since IllegalArgumentException can be
138                     * thrown for just using the wrong number of arguments.
139                     */
140
141                    if (o != null) {
142                        passed = false;
143                        System.err.println("Error: Created new enum object!");
144                        System.err.println(o.getClass());
145                        System.err.println(o.toString());
146                    }
147                } catch (IllegalArgumentException iae) {}
148
149            }
150        }
151
152        if (!passed)
153            throw new RuntimeException("Error during testing.");
154    }
155
156
157    /*
158     * Should be final and not abstract.
159     */
160    @ExpectedModifiers(Modifier.FINAL|Modifier.STATIC)
161    enum AnotherEnum {
162        YELLOW,
163        CYAN,
164        MAGENTA;
165    }
166
167    /*
168     * Should be neither final nor abstract.
169     */
170    @ExpectedModifiers(Modifier.STATIC)
171    enum YetAnotherEnum {
172        GREEN {
173            int value(){ return 1;}
174        },
175
176        ORANGE {
177            int value(){ return 2;}
178        },
179
180        VIOLET {
181            int value(){ return 3;}
182        };
183
184        int value(){ return 0;}
185    }
186
187    /*
188     * Should be abstract and not final.
189     */
190    @ExpectedModifiers(Modifier.ABSTRACT|Modifier.STATIC)
191    enum OneMoreEnum {
192        SANGUINE {
193            int value(){ return 1;}
194        },
195
196        VERDANT {
197            int value(){ return 2;}
198        },
199
200        CERULEAN {
201            int value(){ return 3;}
202        };
203
204        abstract int value();
205    }
206}
207
208@Retention(RetentionPolicy.RUNTIME)
209@interface ExpectedModifiers {
210    int value();
211}
212