    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.lang3;
    018
    019    import java.util.ArrayList;
    020    import java.util.Arrays;
    021    import java.util.LinkedHashMap;
    022    import java.util.List;
    023    import java.util.Map;
    024    import java.util.EnumSet;
    025
    026    /**
    027     * <p>Utility library to provide helper methods for Java enums.</p>
    028     *
    029     * <p>#ThreadSafe#</p>
    030     *
    031     * @since 3.0
    032     * @version $Id: EnumUtils.java 1199894 2011-11-09 17:53:59Z ggregory $
    033     */
    034    public class EnumUtils {
    035
    036        /**
    037         * This constructor is public to permit tools that require a JavaBean
    038         * instance to operate.
    039         */
    040        public EnumUtils() {
    041        }
    042
    043        /**
    044         * <p>Gets the {@code Map} of enums by name.</p>
    045         *
    046         * <p>This method is useful when you need a map of enums by name.</p>
    047         *
    048         * @param <E> the type of the enumeration
    049         * @param enumClass  the class of the enum to query, not null
    050         * @return the modifiable map of enum names to enums, never null
    051         */
    052        public static <E extends Enum<E>> Map<String, E> getEnumMap(Class<E> enumClass) {
    053            Map<String, E> map = new LinkedHashMap<String, E>();
    054            for (E e: enumClass.getEnumConstants()) {
    055                map.put(e.name(), e);
    056            }
    057            return map;
    058        }
    059
    060        /**
    061         * <p>Gets the {@code List} of enums.</p>
    062         *
    063         * <p>This method is useful when you need a list of enums rather than an array.</p>
    064         *
    065         * @param <E> the type of the enumeration
    066         * @param enumClass  the class of the enum to query, not null
    067         * @return the modifiable list of enums, never null
    068         */
    069        public static <E extends Enum<E>> List<E> getEnumList(Class<E> enumClass) {
    070            return new ArrayList<E>(Arrays.asList(enumClass.getEnumConstants()));
    071        }
    072
    073        /**
    074         * <p>Checks if the specified name is a valid enum for the class.</p>
    075         *
    076         * <p>This method differs from {@link Enum#valueOf} in that checks if the name is
    077         * a valid enum without needing to catch the exception.</p>
    078         *
    079         * @param <E> the type of the enumeration
    080         * @param enumClass  the class of the enum to query, not null
    081         * @param enumName   the enum name, null returns false
    082         * @return true if the enum name is valid, otherwise false
    083         */
    084        public static <E extends Enum<E>> boolean isValidEnum(Class<E> enumClass, String enumName) {
    085            if (enumName == null) {
    086                return false;
    087            }
    088            try {
    089                Enum.valueOf(enumClass, enumName);
    090                return true;
    091            } catch (IllegalArgumentException ex) {
    092                return false;
    093            }
    094        }
    095
    096        /**
    097         * <p>Gets the enum for the class, returning {@code null} if not found.</p>
    098         *
    099         * <p>This method differs from {@link Enum#valueOf} in that it does not throw an exception
    100         * for an invalid enum name.</p>
    101         *
    102         * @param <E> the type of the enumeration
    103         * @param enumClass  the class of the enum to query, not null
    104         * @param enumName   the enum name, null returns null
    105         * @return the enum, null if not found
    106         */
    107        public static <E extends Enum<E>> E getEnum(Class<E> enumClass, String enumName) {
    108            if (enumName == null) {
    109                return null;
    110            }
    111            try {
    112                return Enum.valueOf(enumClass, enumName);
    113            } catch (IllegalArgumentException ex) {
    114                return null;
    115            }
    116        }
    117
    118        /**
    119         * <p>Creates a long bit vector representation of the given subset of an Enum.</p>
    120         *
    121         * <p>This generates a value that is usable by {@link EnumUtils#processBitVector}.</p>
    122         *
    123         * <p>Do not use this method if you have more than 64 values in your Enum, as this
    124         * would create a value greater than a long can hold.</p>
    125         *
    126         * @param enumClass the class of the enum we are working with, not {@code null}
    127         * @param values    the values we want to convert, not {@code null}
    128         * @param <E>       the type of the enumeration
    129         * @return a long whose binary value represents the given set of enum values.
    130         * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
    131         * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
    132         * @since 3.0.1
    133         */
    134        public static <E extends Enum<E>> long generateBitVector(Class<E> enumClass, Iterable<E> values) {
    135            checkBitVectorable(enumClass);
    136            Validate.notNull(values);
    137            long total = 0;
    138            for (E constant : values) {
    139                total |= 1 << constant.ordinal();
    140            }
    141            return total;
    142        }
    143
    144        /**
    145         * <p>Creates a long bit vector representation of the given array of Enum values.</p>
    146         *
    147         * <p>This generates a value that is usable by {@link EnumUtils#processBitVector}.</p>
    148         *
    149         * <p>Do not use this method if you have more than 64 values in your Enum, as this
    150         * would create a value greater than a long can hold.</p>
    151         *
    152         * @param enumClass the class of the enum we are working with, not {@code null}
    153         * @param values    the values we want to convert, not {@code null}
    154         * @param <E>       the type of the enumeration
    155         * @return a long whose binary value represents the given set of enum values.
    156         * @throws NullPointerException if {@code enumClass} or {@code values} is {@code null}
    157         * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
    158         * @since 3.0.1
    159         */
    160        public static <E extends Enum<E>> long generateBitVector(Class<E> enumClass, E... values) {
    161            Validate.noNullElements(values);
    162            return generateBitVector(enumClass, Arrays.<E> asList(values));
    163        }
    164
    165        /**
    166         * <p>Convert a long value created by {@link EnumUtils#generateBitVector} into the set of
    167         * enum values that it represents.</p>
    168         *
    169         * <p>If you store this value, beware any changes to the enum that would affect ordinal values.</p>
    170         * @param enumClass the class of the enum we are working with, not {@code null}
    171         * @param value     the long value representation of a set of enum values
    172         * @param <E>       the type of the enumeration
    173         * @return a set of enum values
    174         * @throws NullPointerException if {@code enumClass} is {@code null}
    175         * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
    176         * @since 3.0.1
    177         */
    178        public static <E extends Enum<E>> EnumSet<E> processBitVector(Class<E> enumClass, long value) {
    179            final E[] constants = checkBitVectorable(enumClass).getEnumConstants();
    180            final EnumSet<E> results = EnumSet.noneOf(enumClass);
    181            for (E constant : constants) {
    182                if ((value & 1 << constant.ordinal()) != 0) {
    183                    results.add(constant);
    184                }
    185            }
    186            return results;
    187        }
    188
    189        /**
    190         * Validate that {@code enumClass} is compatible with representation in a {@code long}.
    191         * @param <E> the type of the enumeration
    192         * @param enumClass to check
    193         * @return {@code enumClass}
    194         * @throws NullPointerException if {@code enumClass} is {@code null}
    195         * @throws IllegalArgumentException if {@code enumClass} is not an enum class or has more than 64 values
    196         * @since 3.0.1
    197         */
    198        private static <E extends Enum<E>> Class<E> checkBitVectorable(Class<E> enumClass) {
    199            Validate.notNull(enumClass, "EnumClass must be defined.");
    200
    201            final E[] constants = enumClass.getEnumConstants();
    202            Validate.isTrue(constants != null, "%s does not seem to be an Enum type", enumClass);
    203            Validate.isTrue(constants.length <= Long.SIZE, "Cannot store %s %s values in %s bits", constants.length,
    204                enumClass.getSimpleName(), Long.SIZE);
    205
    206            return enumClass;
    207        }
    208    }