blob: 250f56eba80c0db4680c9eb79f9565f09acceb56 [file] [log] [blame]
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package javax.print.attribute;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
/**
* Class {@code EnumSyntax} is an abstract base class providing the common
* implementation of all "type safe enumeration" objects. An enumeration class
* (which extends class {@code EnumSyntax}) provides a group of enumeration
* values (objects) that are singleton instances of the enumeration class; for
* example:
*
* <pre>
* public class Bach extends EnumSyntax {
* public static final Bach JOHANN_SEBASTIAN = new Bach(0);
* public static final Bach WILHELM_FRIEDEMANN = new Bach(1);
* public static final Bach CARL_PHILIP_EMMANUEL = new Bach(2);
* public static final Bach JOHANN_CHRISTIAN = new Bach(3);
* public static final Bach P_D_Q = new Bach(4);
*
* private static final String[] stringTable = {
* "Johann Sebastian Bach",
* "Wilhelm Friedemann Bach",
* "Carl Philip Emmanuel Bach",
* "Johann Christian Bach",
* "P.D.Q. Bach"
* };
*
* protected String[] getStringTable() {
* return stringTable;
* }
*
* private static final Bach[] enumValueTable = {
* JOHANN_SEBASTIAN,
* WILHELM_FRIEDEMANN,
* CARL_PHILIP_EMMANUEL,
* JOHANN_CHRISTIAN,
* P_D_Q
* };
*
* protected EnumSyntax[] getEnumValueTable() {
* return enumValueTable;
* }
* }
* </pre>
* You can then write code that uses the {@code ==} and {@code !=} operators to
* test enumeration values; for example:
* <pre>
* Bach theComposer;
* . . .
* if (theComposer == Bach.JOHANN_SEBASTIAN) {
* System.out.println ("The greatest composer of all time!");
* }
* </pre>
* The {@code equals()} method for an enumeration class just does a test for
* identical objects ({@code ==}).
* <p>
* You can convert an enumeration value to a string by calling
* {@link #toString() toString()}. The string is obtained from a table supplied
* by the enumeration class.
* <p>
* Under the hood, an enumeration value is just an integer, a different integer
* for each enumeration value within an enumeration class. You can get an
* enumeration value's integer value by calling {@link #getValue() getValue()}.
* An enumeration value's integer value is established when it is constructed
* (see {@link #EnumSyntax(int) EnumSyntax(int)}). Since the constructor is
* protected, the only possible enumeration values are the singleton objects
* declared in the enumeration class; additional enumeration values cannot be
* created at run time.
* <p>
* You can define a subclass of an enumeration class that extends it with
* additional enumeration values. The subclass's enumeration values' integer
* values need not be distinct from the superclass's enumeration values' integer
* values; the {@code ==}, {@code !=}, {@code equals()}, and {@code toString()}
* methods will still work properly even if the subclass uses some of the same
* integer values as the superclass. However, the application in which the
* enumeration class and subclass are used may need to have distinct integer
* values in the superclass and subclass.
*
* @author David Mendenhall
* @author Alan Kaminsky
*/
public abstract class EnumSyntax implements Serializable, Cloneable {
/**
* Use serialVersionUID from JDK 1.4 for interoperability.
*/
private static final long serialVersionUID = -2739521845085831642L;
/**
* This enumeration value's integer value.
*
* @serial
*/
private int value;
/**
* Construct a new enumeration value with the given integer value.
*
* @param value Integer value
*/
protected EnumSyntax(int value) {
this.value = value;
}
/**
* Returns this enumeration value's integer value.
*
* @return the value
*/
public int getValue() {
return value;
}
/**
* Returns a clone of this enumeration value, which to preserve the
* semantics of enumeration values is the same object as this enumeration
* value.
*/
public Object clone() {
return this;
}
/**
* Returns a hash code value for this enumeration value. The hash code is
* just this enumeration value's integer value.
*/
public int hashCode() {
return value;
}
/**
* Returns a string value corresponding to this enumeration value.
*/
public String toString() {
String[] theTable = getStringTable();
int theIndex = value - getOffset();
return
theTable != null && theIndex >= 0 && theIndex < theTable.length ?
theTable[theIndex] :
Integer.toString (value);
}
/**
* During object input, convert this deserialized enumeration instance to
* the proper enumeration value defined in the enumeration attribute class.
*
* @return The enumeration singleton value stored at index <i>i</i>-<i>L</i>
* in the enumeration value table returned by
* {@link #getEnumValueTable() getEnumValueTable()}, where <i>i</i>
* is this enumeration value's integer value and <i>L</i> is the
* value returned by {@link #getOffset() getOffset()}
* @throws ObjectStreamException if the stream can't be deserialised
* @throws InvalidObjectException if the enumeration value table is
* {@code null}, this enumeration value's integer value does not
* correspond to an element in the enumeration value table, or the
* corresponding element in the enumeration value table is
* {@code null}. (Note:
* {@link InvalidObjectException InvalidObjectException} is a
* subclass of {@link ObjectStreamException ObjectStreamException},
* which {@code readResolve()} is declared to throw.)
*/
protected Object readResolve() throws ObjectStreamException {
EnumSyntax[] theTable = getEnumValueTable();
if (theTable == null) {
throw new InvalidObjectException(
"Null enumeration value table for class " +
getClass());
}
int theOffset = getOffset();
int theIndex = value - theOffset;
if (0 > theIndex || theIndex >= theTable.length) {
throw new InvalidObjectException
("Integer value = " + value + " not in valid range " +
theOffset + ".." + (theOffset + theTable.length - 1) +
"for class " + getClass());
}
EnumSyntax result = theTable[theIndex];
if (result == null) {
throw new InvalidObjectException
("No enumeration value for integer value = " +
value + "for class " + getClass());
}
return result;
}
// Hidden operations to be implemented in a subclass.
/**
* Returns the string table for this enumeration value's enumeration class.
* The enumeration class's integer values are assumed to lie in the range
* <i>L</i>..<i>L</i>+<i>N</i>-1, where <i>L</i> is the value returned by
* {@link #getOffset() getOffset()} and <i>N</i> is the length of the string
* table. The element in the string table at index <i>i</i>-<i>L</i> is the
* value returned by {@link #toString() toString()} for the enumeration
* value whose integer value is <i>i</i>. If an integer within the above
* range is not used by any enumeration value, leave the corresponding table
* element {@code null}.
* <p>
* The default implementation returns {@code null}. If the enumeration class
* (a subclass of class {@code EnumSyntax}) does not override this method to
* return a {@code non-null} string table, and the subclass does not
* override the {@link #toString() toString()} method, the base class
* {@link #toString() toString()} method will return just a string
* representation of this enumeration value's integer value.
*
* @return the string table
*/
protected String[] getStringTable() {
return null;
}
/**
* Returns the enumeration value table for this enumeration value's
* enumeration class. The enumeration class's integer values are assumed to
* lie in the range <i>L</i>..<i>L</i>+<i>N</i>-1, where <i>L</i> is the
* value returned by {@link #getOffset() getOffset()} and <i>N</i> is the
* length of the enumeration value table. The element in the enumeration
* value table at index <i>i</i>-<i>L</i> is the enumeration value object
* whose integer value is <i>i</i>; the {@link #readResolve() readResolve()}
* method needs this to preserve singleton semantics during deserialization
* of an enumeration instance. If an integer within the above range is not
* used by any enumeration value, leave the corresponding table element
* {@code null}.
* <p>
* The default implementation returns {@code null}. If the enumeration class
* (a subclass of class EnumSyntax) does not override this method to return
* a {@code non-null} enumeration value table, and the subclass does not
* override the {@link #readResolve() readResolve()} method, the base class
* {@link #readResolve() readResolve()} method will throw an exception
* whenever an enumeration instance is deserialized from an object input
* stream.
*
* @return the value table
*/
protected EnumSyntax[] getEnumValueTable() {
return null;
}
/**
* Returns the lowest integer value used by this enumeration value's
* enumeration class.
* <p>
* The default implementation returns 0. If the enumeration class (a
* subclass of class {@code EnumSyntax}) uses integer values starting at
* other than 0, override this method in the subclass.
*
* @return the offset of the lowest enumeration value
*/
protected int getOffset() {
return 0;
}
}