/* * 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: * *
 *     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;
 *         }
 *     }
 * 
* You can then write code that uses the {@code ==} and {@code !=} operators to * test enumeration values; for example: *
 *     Bach theComposer;
 *     . . .
 *     if (theComposer == Bach.JOHANN_SEBASTIAN) {
 *         System.out.println ("The greatest composer of all time!");
 *     }
 * 
* The {@code equals()} method for an enumeration class just does a test for * identical objects ({@code ==}). *

* 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. *

* 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. *

* 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-L * in the enumeration value table returned by * {@link #getEnumValueTable() getEnumValueTable()}, where i * is this enumeration value's integer value and L 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 * L..L+N-1, where L is the value returned by * {@link #getOffset() getOffset()} and N is the length of the string * table. The element in the string table at index i-L is the * value returned by {@link #toString() toString()} for the enumeration * value whose integer value is i. If an integer within the above * range is not used by any enumeration value, leave the corresponding table * element {@code null}. *

* 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 L..L+N-1, where L is the * value returned by {@link #getOffset() getOffset()} and N is the * length of the enumeration value table. The element in the enumeration * value table at index i-L is the enumeration value object * whose integer value is 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}. *

* 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. *

* 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; } }