001/* 002 * Copyright (C) 2011 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 005 * in compliance with the License. You may obtain a copy of the License at 006 * 007 * http://www.apache.org/licenses/LICENSE-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, software distributed under the License 010 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 011 * or implied. See the License for the specific language governing permissions and limitations under 012 * the License. 013 */ 014 015package com.google.common.base; 016 017import static com.google.common.base.Preconditions.checkNotNull; 018 019import com.google.common.annotations.GwtIncompatible; 020import com.google.common.annotations.J2ktIncompatible; 021import java.io.Serializable; 022import java.lang.ref.WeakReference; 023import java.lang.reflect.Field; 024import java.util.EnumSet; 025import java.util.HashMap; 026import java.util.Map; 027import java.util.WeakHashMap; 028import javax.annotation.CheckForNull; 029 030/** 031 * Utility methods for working with {@link Enum} instances. 032 * 033 * @author Steve McKay 034 * @since 9.0 035 */ 036@GwtIncompatible 037@J2ktIncompatible 038@ElementTypesAreNonnullByDefault 039public final class Enums { 040 041 private Enums() {} 042 043 /** 044 * Returns the {@link Field} in which {@code enumValue} is defined. For example, to get the {@code 045 * Description} annotation on the {@code GOLF} constant of enum {@code Sport}, use {@code 046 * Enums.getField(Sport.GOLF).getAnnotation(Description.class)}. 047 * 048 * @since 12.0 049 */ 050 @GwtIncompatible // reflection 051 public static Field getField(Enum<?> enumValue) { 052 Class<?> 053 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 an optional enum constant for the given type, using {@link Enum#valueOf}. If the 063 * constant does not exist, {@link Optional#absent} is returned. A common use case is for parsing 064 * user input or falling back to a default enum constant. For example, {@code 065 * Enums.getIfPresent(Country.class, countryInput).or(Country.DEFAULT);} 066 * 067 * @since 12.0 068 */ 069 public static <T extends Enum<T>> Optional<T> getIfPresent(Class<T> enumClass, String value) { 070 checkNotNull(enumClass); 071 checkNotNull(value); 072 return Platform.getEnumIfPresent(enumClass, value); 073 } 074 075 @GwtIncompatible // java.lang.ref.WeakReference 076 private static final Map<Class<? extends Enum<?>>, Map<String, WeakReference<? extends Enum<?>>>> 077 enumConstantCache = new WeakHashMap<>(); 078 079 @GwtIncompatible // java.lang.ref.WeakReference 080 private static <T extends Enum<T>> Map<String, WeakReference<? extends Enum<?>>> populateCache( 081 Class<T> enumClass) { 082 Map<String, WeakReference<? extends Enum<?>>> result = new HashMap<>(); 083 for (T enumInstance : EnumSet.allOf(enumClass)) { 084 result.put(enumInstance.name(), new WeakReference<Enum<?>>(enumInstance)); 085 } 086 enumConstantCache.put(enumClass, result); 087 return result; 088 } 089 090 @GwtIncompatible // java.lang.ref.WeakReference 091 static <T extends Enum<T>> Map<String, WeakReference<? extends Enum<?>>> getEnumConstants( 092 Class<T> enumClass) { 093 synchronized (enumConstantCache) { 094 Map<String, WeakReference<? extends Enum<?>>> constants = enumConstantCache.get(enumClass); 095 if (constants == null) { 096 constants = populateCache(enumClass); 097 } 098 return constants; 099 } 100 } 101 102 /** 103 * Returns a serializable converter that converts between strings and {@code enum} values of type 104 * {@code enumClass} using {@link Enum#valueOf(Class, String)} and {@link Enum#name()}. The 105 * converter will throw an {@code IllegalArgumentException} if the argument is not the name of any 106 * enum constant in the specified enum. 107 * 108 * @since 16.0 109 */ 110 @GwtIncompatible 111 public static <T extends Enum<T>> Converter<String, T> stringConverter(Class<T> enumClass) { 112 return new StringConverter<>(enumClass); 113 } 114 115 @GwtIncompatible 116 private static final class StringConverter<T extends Enum<T>> extends Converter<String, T> 117 implements Serializable { 118 119 private final Class<T> enumClass; 120 121 StringConverter(Class<T> enumClass) { 122 this.enumClass = checkNotNull(enumClass); 123 } 124 125 @Override 126 protected T doForward(String value) { 127 return Enum.valueOf(enumClass, value); 128 } 129 130 @Override 131 protected String doBackward(T enumValue) { 132 return enumValue.name(); 133 } 134 135 @Override 136 public boolean equals(@CheckForNull Object object) { 137 if (object instanceof StringConverter) { 138 StringConverter<?> that = (StringConverter<?>) object; 139 return this.enumClass.equals(that.enumClass); 140 } 141 return false; 142 } 143 144 @Override 145 public int hashCode() { 146 return enumClass.hashCode(); 147 } 148 149 @Override 150 public String toString() { 151 return "Enums.stringConverter(" + enumClass.getName() + ".class)"; 152 } 153 154 private static final long serialVersionUID = 0L; 155 } 156}