In Effective Java, 2nd Ed., Joshua Bloch develops the "extensible enum pattern" (item 34). Since enums cannot be subclassed, he proposes unifying groups of related enums by having each enum implement a common type, i.e. interface. This allows enums to be referred to by their unifying type name. The obvious problem with this solution is that type safety is somewhat compromised because it is at least theoretically possible to substitute any non-enum object for an enum by simply creating a class that implements the unifying interface.
To address this problem, a solution is proposed. Here is the method declaration used from the book that takes an enum. The sample application has two enums (BasicOperation
and ExtendedOperation
), both of which implement a unifying type interface called Operation
. The method is designed to accepted any enum of the proper type:
private static <T extends Enum<T> & Operation> void test(
Class<T> opset, double x, double y) {
:
:
}
The reason this works is because the generic method type parameter assures that the class literal supplied as the first argument to the function is both an enum type and an Operation type.
Here is some code from an enum that I am using. This enum is one of a group of enums that I use to describe the metadata for a database column from any of several database tables I am using in my application. Each table has it's own enum that describes these data and they are all unified by implementing the ColumnMetaData<T>
interface (where T
corresponds to the class for the database table).
class Client extends DB { // Class for the Clients table
// MetaData for all the columns in Client
static enum Column implements ColumnMetaData<Client> {
CLIENT_ID (...
:
:
);
}
}
I would like to use a value class in my application called Datum
. It is intended to keep together a database column's value with its column enum.
Here is my problem:
I cannot use a generic method parameter in the constructor for Datum
. How can I tell the compiler that one of the fields in Datum
must implement both ColumnMetaData<table>
and Enum<table.Column>
? Currently, I am using the following:
static class Datum {
private final Object val;
private final ColumnMetaData<? extends DB > col;
private Datum(Object val, ColumnMetaData<? extends DB> col) {
this.val = val;
this.col = col;
}
// assorted static factories here...
:
:
}
This works, but the value is not recognized as an enum type and I want to use the associated enum constants with EnumSet
and EnumMap
.
Is there an elegant solution I am not seeing?