    001    /*
    002     * Copyright (C) 2011 The Guava Authors
    003     *
    004     * Licensed under the Apache License, Version 2.0 (the "License");
    005     * you may not use this file except in compliance with the License.
    006     * You may obtain a copy of the License at
    007     *
    008     * http://www.apache.org/licenses/LICENSE-2.0
    009     *
    010     * Unless required by applicable law or agreed to in writing, software
    011     * distributed under the License is distributed on an "AS IS" BASIS,
    012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013     * See the License for the specific language governing permissions and
    014     * limitations under the License.
    015     */
    016
    017    package com.google.common.base;
    018
    019    import static com.google.common.base.Preconditions.checkNotNull;
    020
    021    import com.google.common.annotations.Beta;
    022    import com.google.common.annotations.GwtCompatible;
    023    import com.google.common.annotations.GwtIncompatible;
    024
    025    import java.io.Serializable;
    026    import java.lang.reflect.Field;
    027
    028    import javax.annotation.Nullable;
    029
    030    /**
    031     * Utility methods for working with {@link Enum} instances.
    032     *
    033     * @author Steve McKay
    034     *
    035     * @since 9.0
    036     */
    037    @GwtCompatible(emulated = true)
    038    @Beta
    039    public final class Enums {
    040
    041      private Enums() {}
    042
    043      /**
    044       * Returns the {@link Field} in which {@code enumValue} is defined.
    045       * For example, to get the {@code Description} annotation on the {@code GOLF}
    046       * constant of enum {@code Sport}, use
    047       * {@code Enums.getField(Sport.GOLF).getAnnotation(Description.class)}.
    048       *
    049       * @since 12.0
    050       */
    051      @GwtIncompatible("reflection")
    052      public static Field getField(Enum<?> enumValue) {
    053        Class<?> clazz = enumValue.getDeclaringClass();
    054        try {
    055          return clazz.getDeclaredField(enumValue.name());
    056        } catch (NoSuchFieldException impossible) {
    057          throw new AssertionError(impossible);
    058        }
    059      }
    060
    061      /**
    062       * Returns a {@link Function} that maps an {@link Enum} name to the associated
    063       * {@code Enum} constant. The {@code Function} will return {@code null} if the
    064       * {@code Enum} constant does not exist.
    065       *
    066       * @param enumClass the {@link Class} of the {@code Enum} declaring the
    067       *     constant values.
    068       */
    069      public static <T extends Enum<T>> Function<String, T> valueOfFunction(Class<T> enumClass) {
    070        return new ValueOfFunction<T>(enumClass);
    071      }
    072
    073      /**
    074       * A {@link Function} that maps an {@link Enum} name to the associated
    075       * constant, or {@code null} if the constant does not exist.
    076       */
    077      private static final class ValueOfFunction<T extends Enum<T>>
    078          implements Function<String, T>, Serializable {
    079
    080        private final Class<T> enumClass;
    081
    082        private ValueOfFunction(Class<T> enumClass) {
    083          this.enumClass = checkNotNull(enumClass);
    084        }
    085
    086        @Override
    087        public T apply(String value) {
    088          try {
    089            return Enum.valueOf(enumClass, value);
    090          } catch (IllegalArgumentException e) {
    091            return null;
    092          }
    093        }
    094
    095        @Override public boolean equals(@Nullable Object obj) {
    096          return obj instanceof ValueOfFunction &&
    097              enumClass.equals(((ValueOfFunction) obj).enumClass);
    098        }
    099
    100        @Override public int hashCode() {
    101          return enumClass.hashCode();
    102        }
    103
    104        @Override public String toString() {
    105          return "Enums.valueOf(" + enumClass + ")";
    106        }
    107
    108        private static final long serialVersionUID = 0;
    109      }
    110
    111      /**
    112       * Returns an optional enum constant for the given type, using {@link Enum#valueOf}. If the
    113       * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing
    114       * user input or falling back to a default enum constant. For example,
    115       * {@code Enums.getIfPresent(Country.class, countryInput).or(Country.DEFAULT);}
    116       *
    117       * @since 12.0
    118       */
    119      public static <T extends Enum<T>> Optional<T> getIfPresent(Class<T> enumClass, String value) {
    120        checkNotNull(enumClass);
    121        checkNotNull(value);
    122        try {
    123          return Optional.of(Enum.valueOf(enumClass, value));
    124        } catch (IllegalArgumentException iae) {
    125          return Optional.absent();
    126        }
    127      }
    128    }