001: /* Licensed to the Apache Software Foundation (ASF) under one or more
002: * contributor license agreements. See the NOTICE file distributed with
003: * this work for additional information regarding copyright ownership.
004: * The ASF licenses this file to You under the Apache License, Version 2.0
005: * (the "License"); you may not use this file except in compliance with
006: * the License. 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 java.lang;
018:
019: import java.io.Serializable;
020: import java.lang.reflect.Method;
021: import java.security.AccessController;
022: import java.security.PrivilegedExceptionAction;
023:
024: import org.apache.harmony.luni.util.Msg;
025:
026: /**
027: * The superclass of all enumerated types.
028: */
029: public abstract class Enum<E extends Enum<E>> implements Serializable,
030: Comparable<E> {
031:
032: private static final long serialVersionUID = -4300926546619394005L;
033:
034: private final String name;
035:
036: private final int ordinal;
037:
038: /**
039: * Constructor for enum subtypes.
040: *
041: * @param name
042: * the enum constant declared name.
043: * @param ordinal
044: * the enum constant position ordinal.
045: */
046: protected Enum(String name, int ordinal) {
047: this .name = name;
048: this .ordinal = ordinal;
049: }
050:
051: /**
052: * Answers the name of the enum constant. The name is the field as it
053: * appears in the <code>Enum</code> declaration.
054: *
055: * @return the precise enum constant name.
056: * @see #toString()
057: */
058: public final String name() {
059: return name;
060: }
061:
062: /**
063: * Answers the position of the enum constant in the declaration. The first
064: * constant has and ordinal value of zero.
065: *
066: * @return the constant's ordinal value.
067: */
068: public final int ordinal() {
069: return ordinal;
070: }
071:
072: /**
073: * Answer a string representation of the receiver suitable for display to a
074: * programmer.
075: *
076: * @return the displayable string name.
077: */
078: @Override
079: public String toString() {
080: return name;
081: }
082:
083: /**
084: * Answers true only if the receiver is equal to the argument. Since enums
085: * are unique this is equivalent to an identity test.
086: *
087: * @return true if the receiver and argument are equal, otherwise return
088: * false.
089: */
090: @Override
091: public final boolean equals(Object other) {
092: return this == other;
093: }
094:
095: /**
096: * Answers the hash of the receiver.
097: *
098: * @return the hash code.
099: */
100: @Override
101: public final int hashCode() {
102: return ordinal + (name == null ? 0 : name.hashCode());
103: }
104:
105: /**
106: * Enums are singletons, they may not be cloned. This method always throws a
107: * {@link CloneNotSupportedException}.
108: *
109: * @return does not return.
110: */
111: @Override
112: protected final Object clone() throws CloneNotSupportedException {
113: // KA004=Enums may not be cloned
114: throw new CloneNotSupportedException(Msg.getString("KA004")); //$NON-NLS-1$
115: }
116:
117: /**
118: * Answers the comparative ordering of the receiver and the given argument.
119: * If the receiver is naturally ordered before the actual argument then the
120: * result is negative, if the receiver is naturally ordered in equal
121: * position to the actual argument then the result is zero, and if the
122: * receiver is naturally ordered after the actual argument then the result
123: * is positive.
124: *
125: * @return negative, zero, or positive value depending upon before, equal,
126: * or after natural order respectively.
127: * @see Comparable#compareTo(Object)
128: */
129: public final int compareTo(E o) {
130: return ordinal - o.ordinal;
131: }
132:
133: /**
134: * Answers the enum constant's declaring class.
135: *
136: * @return the class object representing the constant's enum type.
137: */
138: @SuppressWarnings("unchecked")
139: public final Class<E> getDeclaringClass() {
140: Class<?> myClass = getClass();
141: Class<?> mySuperClass = myClass.getSuperclass();
142: if (Enum.class == mySuperClass) {
143: return (Class<E>) myClass;
144: }
145: return (Class<E>) mySuperClass;
146: }
147:
148: /**
149: * Answers the named constant of the given enum type.
150: *
151: * @param enumType
152: * the class of the enumerated type to search for the constant
153: * value.
154: * @param name
155: * the name of the constant value to find.
156: * @return the enum constant
157: * @throws NullPointerException
158: * if either the <code>enumType</code> or <code>name</code>
159: * are <code>null</code>.
160: * @throws IllegalArgumentException
161: * if <code>enumType</code> is not an enumerated type or does
162: * not have a constant value called <code>name</code>.
163: */
164: public static <T extends Enum<T>> T valueOf(Class<T> enumType,
165: String name) {
166: if ((enumType == null) || (name == null)) {
167: // KA001=Argument must not be null
168: throw new NullPointerException(Msg.getString("KA001")); //$NON-NLS-1$
169: }
170: T[] values = getValues(enumType);
171: if (values == null) {
172: // KA005={0} is not an enum type
173: throw new IllegalArgumentException(Msg.getString(
174: "KA005", enumType)); //$NON-NLS-1$
175: }
176: for (T enumConst : values) {
177: if (enumConst.name.equals(name)) {
178: return enumConst;
179: }
180: }
181: // KA006={0} is not a constant in the enum type {1}
182: throw new IllegalArgumentException(Msg.getString("KA006", name, //$NON-NLS-1$
183: enumType));
184: }
185:
186: /*
187: * Helper to invoke the values() static method on T and answer the result.
188: * Returns null if there is a problem.
189: */
190: @SuppressWarnings("unchecked")
191: static <T extends Enum<T>> T[] getValues(final Class<T> enumType) {
192: try {
193: Method values = AccessController
194: .doPrivileged(new PrivilegedExceptionAction<Method>() {
195: public Method run() throws Exception {
196: Method valsMethod = enumType.getMethod(
197: "values", //$NON-NLS-1$
198: (Class[]) null);
199: valsMethod.setAccessible(true);
200: return valsMethod;
201: }
202: });
203: return (T[]) values.invoke(enumType, (Object[]) null);
204: } catch (Exception e) {
205: return null;
206: }
207: }
208: }
|