test/tools/javac/enum/EnumImplicitPrivateConstructor.java

changeset 1
9a66ca7c79fa
child 289
84061bd68019
     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 +}

mercurial