net.lucidviews.util
Class EnumValue<T extends EnumValue>

java.lang.Object
  extended by net.lucidviews.util.EnumValue<T>
Type Parameters:
T - the EnumValue sub class
All Implemented Interfaces:
Serializable
Direct Known Subclasses:
Properties.EnumParamMustExist, Strings.EnumValueMustBeValid

public abstract class EnumValue<T extends EnumValue>
extends Object
implements Serializable

Base-class for defining an enumeration type.

To define an enumeration extend this class, implementing the getEnumeration method, and create instances for each value in your enumeration.
In Java5, use of generics allows the exact type (sub-class) of EnumValue to be associated with the Enumeration.

For example:

public class DistanceUnit extends EnumValue<DistanceUnit>
{
  // create a list for the enumeration values
  public static final Enumeration<DistanceUnit> ENUMERATION = new Enumeration<DistanceUnit>();
  
  // provide the EnumValue base class with access to the enumeration
  public Enumeration<DistanceUnit> getEnumeration()
  {
    return ENUMERATION;
  }
  
  // define the enumeration values
  public static final DistanceUnit METRE = new DistanceUnit();
  public static final DistanceUnit YARD = new DistanceUnit();
  public static final DistanceUnit KILOMETRE = new DistanceUnit();
  public static final DistanceUnit MILE = new DistanceUnit();
  
  // make the constructor private to protect this enum
  private DistanceUnit()
  {
  }
}

It is essential that all constructors of the class are protected or private so that no other instances can be created, which would extend your enumeration with values that you did not define. This includes the default constructor, which must be declared protected or private if you define no other constructor.
However, it is recommended that you assign a user-friendly text string to each of your enumeration values. To do this you will need to define a constructor in your enum class like this:
  ...
  // define the enumeration values
  public static final DistanceUnit METRE = new DistanceUnit( "metre" );
  public static final DistanceUnit YARD = new DistanceUnit( "yard" );
  public static final DistanceUnit KILOMETRE = new DistanceUnit( "kilometre" );
  public static final DistanceUnit MILE = new DistanceUnit( "mile" );
  
  // make the constructor private to protect this enum
  private DistanceUnit( String unitName )
  {
    super( unitName );
  }
  ...


The enumeration type is now ready to use. Using the enumeration type makes the source code more readable and ensures the compiler performs some type checking on parameter values.
For example, the method:
public void setDistanceUnit( int distanceUnit )
would become
public void setDistanceUnit( DistanceUnit newValue )
The primary advantage is that the newValue must be one of the constants defined by the DistanceUnit class - in the first interface, the distanceUnit could be any int value and the method would need to perform some range checks first and throw an exception. With enumerations the checks are done at compile time and no exception needs to be caught.

Enumeration values can be taken from the exported constants in the EnumValue sub class or derived from their index or user-friendly name.
For example, if a string value "mile" is read from a configuration file, the enumeration value can be looked-up:
String distanceUnitName = ...;
DistanceUnit distanceUnit = DistanceUnit.ENUMERATION.lookupValue( distanceUnitName );


IMPORTANT
Use the == operator, not the equals method to evaluate or compare EnumValues.
The equals method performs an internal representation comparision and is provided so that string and integer values will match the text-value and index of an enumeration value.
Each enumeration value is a new, unique constant and should be compared directly. For example:
String distanceUnitName = ...;
DistanceUnit distanceUnit = DistanceUnit.ENUMERATION.lookupValue( distanceUnitName );
if (distanceUnit == DistanceUnit.MILE)
{
  ...
}


Sub Enumerations
In Java5 the EnumValue class supports sub enumerations - sub lists within an enumeration.
To support sub lists you should define your enum class slightly differently to the definition described above.

Like this:

public class Department<T extends Department> extends EnumValue<T>
{
  // create a list for the enumeration values
  public static final Enumeration<Department> ENUMERATION = new Enumeration<Department>();
  
  // provide the EnumValue base class with access to the enumeration
  public Enumeration<T> getEnumeration()
  {
    // The following cast works only when T = Department.
    // Sub-classes MUST override this method
    // and return an Enumeration of values of that sub type.
    return (Enumeration<T>)ENUMERATION;
  }
  
  // define the enumeration values
  public static final Department<Department> SALES = new Department<Department>( "sales" );
  public static final Department<Department> ACCOUNTS = new Department<Department>( "accounts" );
  public static final Department<Department> OFFICE_SERVICES = new Department<Department>( "office services" );
  
  // protect the constructor to prevent new departments being created
  protected Department( String name )
  {
    super( name );
  }
}

Sub lists can then be defined like so:

public class TechnicalDepartment<T extends TechnicalDepartment> extends Department<T>
{
  // create a list for the enumeration values
  public static final Enumeration<TechnicalDepartment> ENUMERATION = new Enumeration<TechnicalDepartment>( Department.ENUMERATION );
  
  // provide the EnumValue base class with access to the enumeration
  public Enumeration<T> getEnumeration()
  {
    // The following cast works only when T = TechnicalDepartment.
    // Sub-classes MUST override this method
    // and return an Enumeration of values of that sub type.
    return (Enumeration<T>)ENUMERATION;
  }
  
  // define the enumeration values
  public static final TechnicalDepartment<TechnicalDepartment> DEVELOPMENT = new TechnicalDepartment<TechnicalDepartment>( "development" );
  public static final TechnicalDepartment<TechnicalDepartment> SUPPORT = new TechnicalDepartment<TechnicalDepartment>( "support" );
  public static final TechnicalDepartment<TechnicalDepartment> TESTING = new TechnicalDepartment<TechnicalDepartment>( "testing" );
  
  // protect the constructor to prevent new technical departments being created
  protected TechnicalDepartment( String name )
  {
    super( name );
  }
}

As the definition of the class suggests (TechnicalDepartment extends Department) a technical department is a sub type of a department.
The TechnicalDepartments DEVELOPMENT, SUPPORT and TESTING not only make up the sub-list of technical departments but are also part of the Department enumeration.
i.e.

TechnicalDepartment.ENUMERATION.valueOf( "development" )
returns TechnicalDepartment.DEVELOPMENT

Department.ENUMERATION.valueOf( "development" )
returns TechnicalDepartment.DEVELOPMENT

Department.ENUMERATION.valueOf( "sales" )
returns Department.SALES

TechnicalDepartment.ENUMERATION.valueOf( "sales" )
throws a NoSuchElementException

Since:
1.0
Version:
$Revision: 1.4.2.2 $
Author:
Stephen Battey
See Also:
Enumeration, Serialized Form

Field Summary
protected  int _index
          The index of this value within the enumeration.
protected  boolean _isCaseSensitive
          A flag indicating if the text value is case sensitive.
protected  String _textValue
          The user-friendly name associated with this enumeration value.
protected static String ENUMERATION_FIELD_NAME
          The name of the field that sub classes use to hold the Enumeration.
protected static int UNDEFINED_INDEX
          A value assigned to the index variable before the index of the enum value is known.
 
Constructor Summary
protected EnumValue()
          Create an enumeration value with no user-friendly name.
protected EnumValue(String textValue)
          Create an enumeration value that can be identified by the given text.
protected EnumValue(String textValue, boolean isCaseSensitive)
          Create an enumeration value that can be identified by the given text.
 
Method Summary
 int compareTo(T other)
          Compares this value with another enum value for order.
 boolean equals(Object obj)
          
abstract  Enumeration<T> getEnumeration()
          Obtain the enumeration this value belongs to.
 int getIndex()
          Get the index of this enum value within the enumeration list.
 String getTextValue()
          Get the text representation of this enum value.
 int hashCode()
          
 String name()
          A synonym for getTextValue, defined to make switching from enums to EnumValues easier.
 int ordinal()
          A synonym for getIndex, defined to make switching from enums to EnumValues easier.
 String toString()
          
static EnumValue<?> valueOf(Class<? extends EnumValue> enumType, String name)
          Returns the EnumValue of the specified enumeration type with the specified name.
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

UNDEFINED_INDEX

protected static final int UNDEFINED_INDEX
A value assigned to the index variable before the index of the enum value is known.

See Also:
Constant Field Values

ENUMERATION_FIELD_NAME

protected static final String ENUMERATION_FIELD_NAME
The name of the field that sub classes use to hold the Enumeration.

Since:
1.2
See Also:
Constant Field Values

_textValue

protected String _textValue
The user-friendly name associated with this enumeration value.


_isCaseSensitive

protected boolean _isCaseSensitive
A flag indicating if the text value is case sensitive.


_index

protected int _index
The index of this value within the enumeration.

Constructor Detail

EnumValue

protected EnumValue(String textValue,
                    boolean isCaseSensitive)
Create an enumeration value that can be identified by the given text.

Parameters:
textValue - the String that is associated with this enum value
isCaseSensitive - indicates if a String should be associated with this enum value only if the case matches that in the text value

EnumValue

protected EnumValue(String textValue)
Create an enumeration value that can be identified by the given text.
The text will not be treated as case sensitive.

Parameters:
textValue - the String that is associated with this enum value

EnumValue

protected EnumValue()
Create an enumeration value with no user-friendly name.
The value can then only be cross-referenced by its index.

Method Detail

getEnumeration

public abstract Enumeration<T> getEnumeration()
Obtain the enumeration this value belongs to.
See the class JavaDoc, at the top of this page, for information on how to implement this method correctly.

Returns:
a list of enumeration values that this value is part of

getIndex

public int getIndex()
Get the index of this enum value within the enumeration list.

Returns:
the index of this enum value
Since:
1.2

ordinal

public int ordinal()
A synonym for getIndex, defined to make switching from enums to EnumValues easier.

Returns:
the index of this enum value
Since:
1.2
See Also:
getIndex()

getTextValue

public String getTextValue()
Get the text representation of this enum value.

Returns:
the text value of this enum value
Since:
1.2

name

public String name()
A synonym for getTextValue, defined to make switching from enums to EnumValues easier.

Returns:
the text value of this enum value
Since:
1.2
See Also:
getTextValue()

compareTo

public int compareTo(T other)
Compares this value with another enum value for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.
Enum constants are only comparable to other enum constants of the same enum type. The natural order implemented by this method is the order in which the constants are declared.

Parameters:
other - the other enum value
Returns:
an integer that describes if this value is larger, equal or smaller than the other value
Since:
1.2

valueOf

public static EnumValue<?> valueOf(Class<? extends EnumValue> enumType,
                                   String name)
                            throws IllegalArgumentException,
                                   NullPointerException
Returns the EnumValue of the specified enumeration type with the specified name. The name must match with the text value of the enum value. (Extraneous whitespace characters are not permitted.)

Parameters:
enumType - the Class object of the EnumValue from which to return a constant
name - the text value of the enum value to return
Returns:
the EnumValue from the specified enumeration type with the specified name
Throws:
IllegalArgumentException - if the specified enumeration class has no constant with the specified name, or the specified class does not represent an enum type
NullPointerException - if enumType or name is null
Since:
1.2

toString

public String toString()

Overrides:
toString in class Object

hashCode

public int hashCode()

Overrides:
hashCode in class Object

equals

public boolean equals(Object obj)

Overrides:
equals in class Object