/**
* Copyright 2010 Wealthfront Inc. Licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
* or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.kaching.platform.common.values;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Method;
import java.util.Map;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.kaching.platform.common.Option;
/**
* Utility class to help with numbered enums. A numbered enum is one that
* implements {@link NumberedValue}.
*/
public class NumberedEnum {
private static LoadingCache<Class<?>, Map<Integer, Enum<?>>> mappings =
CacheBuilder.newBuilder().build(new CacheLoader<Class<?>, Map<Integer, Enum<?>>>() {
@Override
public Map<Integer, Enum<?>> load(Class<?> from) {
try {
Builder<Integer, Enum<?>> builder = ImmutableMap.<Integer, Enum<?>>builder();
// Multiple casts valid from type parameter bounds declared in valueOf().
Method method = from.getMethod("values");
method.setAccessible(true);
Enum<?>[] values = (Enum<?>[]) method.invoke(null);
for (Enum<?> value : values) {
builder.put(((NumberedValue) value).getNumber(), value);
}
return builder.build();
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
});
/**
* Returns the enum constant of the specified enum type with the specified
* number. (This function is similar to {@link Enum#valueOf(Class, String)}.)
*
* @throws NullPointerException if the {@code value} is {@code null}
*/
@SuppressWarnings("unchecked")
public static <E extends Enum<E> & NumberedValue> Option<E> valueOf(final Class<E> type, int number) {
checkNotNull(type);
E value = (E) mappings.getUnchecked(type).get(number);
return Option.of(value);
}
}