Java Forum / General / June 2005
enum aliases
Roedy Green - 26 Jun 2005 23:21 GMT IT would be nice if there were an easy way to have both valueOf and toString aliases for enums.
Why?
To allow you to use reserved words like true, false, default, null as your enum string constants.
to allow additional variants on input e.g. for "yes" also allow "true" "t" "f".
To change the way the enum displays e.g. to change the language. to change default/usual to whatever the default value actually is. Any ideas on how to implement that cleanly?
 Signature Bush crime family lost/embezzled $3 trillion from Pentagon. Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video. http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green. See http://mindprod.com/iraq.html photos of Bush's war crimes
Lasse Reichstein Nielsen - 27 Jun 2005 01:02 GMT > IT would be nice if there were an easy way to have both valueOf and > toString aliases for enums.
> Why? > > To allow you to use reserved words like true, false, default, null as > your enum string constants. You can overwrite toString if you want to. There can obviosuly only be one default string representation, so if you want both the enum name and its alias, you need two functions, so just write your own myToString().
> to allow additional variants on input e.g. for "yes" also allow "true" > "t" "f". The valueOf method is implicitly defined on all enum classes, and you are not allowed to overwrite it. But then, you can just create your own.
> To change the way the enum displays e.g. to change the language. to > change default/usual to whatever the default value actually is. You should not depend on the name of the enum constant for its display. If you need to display it in a way that might change, then it is a display concern, and should be kept closer to the display code than to the enum itself. I would just make a map from enum name to presentation.
What is a default in this scenarios?
Anyway: --- public enum EnumTest { TEST("test","trial","query"), SUCCESS("success","yes","true"), FAILURE("failure","fail","no","false");
private static Map<String,EnumTest> aliasMap;
private final String defaultName;
EnumTest(String... aliases) { if (aliasMap == null) { aliasMap = new HashMap<String,EnumTest>(); } for (String alias : aliases) { aliasMap.put(alias, this); } if (aliases.length > 0) { defaultName = aliases[0]; } else { defaultName = name(); } }
static EnumTest valueOfAlias(String alias) { EnumTest value = aliasMap.get(alias); if (value == null) { throw new IllegalArgumentException(alias + " not an alias"); } return value; }
public String toString() { return defaultName; } } ---
I think that qualifies as an "easy way" :) /L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Roedy Green - 28 Jun 2005 07:11 GMT > aliasMap.put(alias, this); then will generate an errormessage
illegal reference to static field from initializer
I don't understand why.
import java.util.HashMap; import java.util.Map;
/** * enum with aliases for string input to valueOf * @author Roedy Green, added comments. * based on posted code by Lasse Reichstein Nielsen lrn@hotpop.com */
public enum Outcome { SUCCESS( "success", "yes", "true" ), FAILURE( "failure", "fail", "no", "false" ), UNDECIDED( "undecided", "maybe" );
/** * maps from alias name to matching enum constant */ private static Map<String, Outcome> aliasMap = new HashMap<String,Outcome>();
/** *the preferred alias to use as the canonical name */ private final String defaultName;
/** * constructor for an enum constant * @param aliases takes String[] specified as a variable length list of strings * representing alternate input values for the aliases. */ Outcome( String... aliases ) {
for ( String alias : aliases ) { aliasMap.put( alias, this ); } if ( aliases.length > 0 ) { defaultName = aliases[0]; } else { // allow some enum constants to have no aliases, work as normal enum constants defaultName = name(); } }
/** * convert string to enum constant * @param alias string representing one of the aliases of one of the enum constants. * @returns enum constant matching String. * @throws IllegalArgumentExeption if alias is not a legal one. */ static Outcome valueOfAlias( String alias ) { Outcome value = aliasMap.get( alias ); if ( value == null ) { throw new IllegalArgumentException( alias + " not a legal Outcome alias" ); } return value; }
/** * The canonical name of this enum constant/variable. */ public String toString() { return defaultName; }
private static final boolean DEBUGGING = true;
/** * test harness * * @param args not used */ public static void main ( String[] args ) { if ( DEBUGGING ) { Outcome o = Outcome.valueOfAlias( "no" ); System.out.println( o ); // prints "failure" } }
 Signature Bush crime family lost/embezzled $3 trillion from Pentagon. Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video. http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green. See http://mindprod.com/iraq.html photos of Bush's war crimes
Lasse Reichstein Nielsen - 28 Jun 2005 20:17 GMT >> aliasMap.put(alias, this); > then will generate an errormessage > > illegal reference to static field from initializer The error message I get from your code is: --- java.lang.ExceptionInInitializerError Caused by: java.lang.NullPointerException at Outcome.<init>(Outcome.java:41) at Outcome.<clinit>(Outcome.java:17) Exception in thread "main" ---
> I don't understand why. You are initializing the static variable "aliasMap" *after* creating the instances of Outcome. Remember that enum values are really static final fields, and they are assigned earlier in the static initialization than other static fields. That means that the "aliasMap" field is null when the constructors try to put values into the map.
If you compare it to my original code, I initialized the map the first time I needed it, to make sure it was not null. That was deliberate :)
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Roedy Green - 30 Jun 2005 04:05 GMT >>> aliasMap.put(alias, this); >> then will generate an errormessage [quoted text clipped - 23 lines] > >/L when I do it your way, I get even more of those static initialiser errors.
You are doing things in the logical order, but Java does not trust you.
 Signature Bush crime family lost/embezzled $3 trillion from Pentagon. Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video. http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green. See http://mindprod.com/iraq.html photos of Bush's war crimes
Roedy Green - 30 Jun 2005 16:09 GMT >when I do it your way, I get even more of those static initialiser >errors. here is my code that works, but is not very smart. It just does a linear search. package com.mindprod.pricelist;
/** * constants for Application categories */ public enum AppCat {
/* short name, description, aliases */
APPLET( "Applet", "Java Applet", "applet" ), APPLICATION( "application", "Java application", "application"), DOCUMENTATION( "documentation", "documentation" , "documentation" ), HYBRID( "hybrid", "Java Applet that can also be run as an application", "hybrid" ), JWS( "Java Web Start" ,"Java Web Start", "jws", "weblet", "webstart", "jaws" ), LIBRARY( "Class" , "Class library", "class", "classes", "library" ), SERVLET( "servlet", "Java Servlet", "servlet" ), UTILITY( "Utility", "non-Java Utility", "utility" );
/** * constructor for an enum constant * @param human output description. * @param ShorName for display * @param description long description * @param aliases other names for string input */ AppCat( String shortName, String description, String... aliases ) { this.shortName = shortName; this.description = description; this.aliases = aliases; }
private String shortName;
private String description;
/** * cannot use String... here, only in parm list * alterate input names for the alias */ private String[] aliases;
public String getShortName() { return shortName; }
public String getDescription() { return description; }
public String[] getAliases() { return aliases; } // you may not redefine valueOf since has been covertly defined in this class
public static AppCat valueOfAlias ( String s ) { try { return valueOf( AppCat.class, s ); } catch ( IllegalArgumentException e ) { // usual method failed, try looking up alias // This seems long winded, why no HashSet? // Because Java won't let me access a static common // lookup in the enum constructors. for ( AppCat candidateEnum : AppCat.values() ) {
for ( String candidateString : candidateEnum.getAliases() ) { if ( candidateString.equalsIgnoreCase( s ) ) { return candidateEnum; } } } // fell out the bottom of search over all enums and aliases // give up
throw new IllegalArgumentException( "unknown Application Category: " + s);
}
} }
 Signature Bush crime family lost/embezzled $3 trillion from Pentagon. Complicit Bush-friendly media keeps mum. Rumsfeld confesses on video. http://www.infowars.com/articles/us/mckinney_grills_rumsfeld.htm
Canadian Mind Products, Roedy Green. See http://mindprod.com/iraq.html photos of Bush's war crimes
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|