test/tools/javac/enum/EnumImplicitPrivateConstructor.java

changeset 0
959103a6100f
child 2525
2eb010b6cb22
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/test/tools/javac/enum/EnumImplicitPrivateConstructor.java	Wed Apr 27 01:34:52 2016 +0800
     1.3 @@ -0,0 +1,211 @@
     1.4 +/*
     1.5 + * Copyright (c) 2004, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * 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 +
    1.34 +import java.util.*;
    1.35 +import java.lang.reflect.*;
    1.36 +import java.lang.annotation.*;
    1.37 +
    1.38 +/*
    1.39 + * Arguably, only the final and abstract should be held in
    1.40 + * ExpectedModifiers; whether or not an enum should be static could be
    1.41 + * inferred from getDeclaringClass and working versions of
    1.42 + * getEnclosingMethod and getEnclosingConstructor.  I.e. if
    1.43 + * getDeclaringClass, getEnclosingMethod, and getEnclosingConstructor
    1.44 + * were all null, the enum is a top-level class and should not be
    1.45 + * static; otherwise, it should be static.
    1.46 + */
    1.47 +
    1.48 +@ExpectedModifiers(Modifier.FINAL)
    1.49 +public enum EnumImplicitPrivateConstructor {
    1.50 +    RED(255, 0, 0),
    1.51 +    GREEN(0, 255, 0),
    1.52 +    BLUE(0, 0, 255);
    1.53 +
    1.54 +    private int r, g, b;
    1.55 +    EnumImplicitPrivateConstructor(int r, int g, int b) {
    1.56 +        this.r = r;
    1.57 +        this.g = g;
    1.58 +        this.b = b;
    1.59 +    }
    1.60 +
    1.61 +    /*
    1.62 +     * Using reflection, Verify that
    1.63 +     * 1. all non-synthetic constructors of enum classes are marked as private.
    1.64 +     * 2. top-level enum classes are marked as static
    1.65 +     * 3. enum's are marked final and abstract as appropriate
    1.66 +     * 4. enum constructors *cannot* be invoked reflectively
    1.67 +     */
    1.68 +    public static void main(String argv[]) throws Exception {
    1.69 +        boolean passed = true;
    1.70 +
    1.71 +        Collection<Class> classes = new LinkedHashSet<Class>();
    1.72 +
    1.73 +        classes.add(Class.forName("EnumImplicitPrivateConstructor"));
    1.74 +        classes.add(Class.forName("EnumImplicitPrivateConstructor$AnotherEnum"));
    1.75 +        classes.add(Class.forName("EnumImplicitPrivateConstructor$YetAnotherEnum"));
    1.76 +        classes.add(Class.forName("EnumImplicitPrivateConstructor$OneMoreEnum"));
    1.77 +
    1.78 +        // Add classes of specialized enum constants
    1.79 +        for(Enum e: YetAnotherEnum.values())
    1.80 +            classes.add(e.getClass());
    1.81 +
    1.82 +        for(Class clazz: classes) {
    1.83 +            System.out.println("Testing class " + clazz);
    1.84 +
    1.85 +            int classModifiers = clazz.getModifiers();
    1.86 +
    1.87 +            // Why is this cast needed?
    1.88 +            ExpectedModifiers em = (ExpectedModifiers)clazz.getAnnotation(ExpectedModifiers.class);
    1.89 +            if (em != null) {
    1.90 +                System.out.println("\tTesting expected modifiers");
    1.91 +                int expected = em.value();
    1.92 +
    1.93 +                if (expected != (classModifiers & (Modifier.ABSTRACT|Modifier.FINAL|Modifier.STATIC))) {
    1.94 +                    passed = false;
    1.95 +                    System.out.println("\tFAILED: Expected 0x" + Integer.toHexString(expected) +
    1.96 +                                       " got 0x" +Integer.toHexString(classModifiers));
    1.97 +                }
    1.98 +            }
    1.99 +
   1.100 +            for(Constructor ctor: clazz.getDeclaredConstructors() ) {
   1.101 +                System.out.println("\tTesting constructor " + ctor);
   1.102 +
   1.103 +                // We don't need no stinkin' access rules
   1.104 +                try {
   1.105 +                    ctor.setAccessible(true);
   1.106 +                } catch (java.security.AccessControlException ex) {
   1.107 +                }
   1.108 +
   1.109 +                int modifiers = ctor.getModifiers();
   1.110 +
   1.111 +                /*
   1.112 +                 * If clazz is for a specialized enum constant, the
   1.113 +                 * class will have the ENUM bit set but clazz.isEnum()
   1.114 +                 * will be false.  A constructor in such a class must
   1.115 +                 * be non-private to allow the parent class to call
   1.116 +                 * the constructor.  Therefore, only impose the
   1.117 +                 * private constructor check for genuine isEnum
   1.118 +                 * classes.
   1.119 +                 */
   1.120 +                if (clazz.isEnum()) {
   1.121 +                    if ((modifiers & Modifier.PRIVATE) == 0 &&
   1.122 +                        ! ctor.isSynthetic() ) {
   1.123 +                        passed = false;
   1.124 +                        System.out.println("\tFAILED: Constructor not marked private: modifiers 0x" +
   1.125 +                                           Integer.toHexString(modifiers));
   1.126 +                    }
   1.127 +                }
   1.128 +
   1.129 +                try {
   1.130 +                    // Should get exception trying to invoke
   1.131 +                    Object o = null;
   1.132 +                    try {
   1.133 +                        o = ctor.newInstance("abc", 123);
   1.134 +                    } catch (IllegalAccessException ex) {
   1.135 +                    }
   1.136 +
   1.137 +                    /*
   1.138 +                     * A better test would query the number (and type)
   1.139 +                     * of parameters and create an appropriate
   1.140 +                     * argument list since IllegalArgumentException can be
   1.141 +                     * thrown for just using the wrong number of arguments.
   1.142 +                     */
   1.143 +
   1.144 +                    if (o != null) {
   1.145 +                        passed = false;
   1.146 +                        System.err.println("Error: Created new enum object!");
   1.147 +                        System.err.println(o.getClass());
   1.148 +                        System.err.println(o.toString());
   1.149 +                    }
   1.150 +                } catch (IllegalArgumentException iae) {}
   1.151 +
   1.152 +            }
   1.153 +        }
   1.154 +
   1.155 +        if (!passed)
   1.156 +            throw new RuntimeException("Error during testing.");
   1.157 +    }
   1.158 +
   1.159 +
   1.160 +    /*
   1.161 +     * Should be final and not abstract.
   1.162 +     */
   1.163 +    @ExpectedModifiers(Modifier.FINAL|Modifier.STATIC)
   1.164 +    enum AnotherEnum {
   1.165 +        YELLOW,
   1.166 +        CYAN,
   1.167 +        MAGENTA;
   1.168 +    }
   1.169 +
   1.170 +    /*
   1.171 +     * Should be neither final nor abstract.
   1.172 +     */
   1.173 +    @ExpectedModifiers(Modifier.STATIC)
   1.174 +    enum YetAnotherEnum {
   1.175 +        GREEN {
   1.176 +            int value(){ return 1;}
   1.177 +        },
   1.178 +
   1.179 +        ORANGE {
   1.180 +            int value(){ return 2;}
   1.181 +        },
   1.182 +
   1.183 +        VIOLET {
   1.184 +            int value(){ return 3;}
   1.185 +        };
   1.186 +
   1.187 +        int value(){ return 0;}
   1.188 +    }
   1.189 +
   1.190 +    /*
   1.191 +     * Should be abstract and not final.
   1.192 +     */
   1.193 +    @ExpectedModifiers(Modifier.ABSTRACT|Modifier.STATIC)
   1.194 +    enum OneMoreEnum {
   1.195 +        SANGUINE {
   1.196 +            int value(){ return 1;}
   1.197 +        },
   1.198 +
   1.199 +        VERDANT {
   1.200 +            int value(){ return 2;}
   1.201 +        },
   1.202 +
   1.203 +        CERULEAN {
   1.204 +            int value(){ return 3;}
   1.205 +        };
   1.206 +
   1.207 +        abstract int value();
   1.208 +    }
   1.209 +}
   1.210 +
   1.211 +@Retention(RetentionPolicy.RUNTIME)
   1.212 +@interface ExpectedModifiers {
   1.213 +    int value();
   1.214 +}

mercurial