enum aliases

Discussion in 'Java' started by Roedy Green, Jun 26, 2005.

  1. Roedy Green

    Roedy Green Guest

    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?

    --
    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, Jun 26, 2005
    #1
    1. Advertising

  2. Roedy Green <> writes:

    > 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
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, Jun 27, 2005
    #2
    1. Advertising

  3. Roedy Green

    Roedy Green Guest

    On Mon, 27 Jun 2005 02:02:23 +0200, Lasse Reichstein Nielsen
    <> wrote or quoted :

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

    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"
    }
    }



    --
    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, Jun 28, 2005
    #3
  4. Roedy Green <> writes:

    > On Mon, 27 Jun 2005 02:02:23 +0200, Lasse Reichstein Nielsen
    > <> wrote or quoted :
    >
    >> 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
    --
    Lasse Reichstein Nielsen -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
     
    Lasse Reichstein Nielsen, Jun 28, 2005
    #4
  5. Roedy Green

    Roedy Green Guest

    On Tue, 28 Jun 2005 21:17:53 +0200, Lasse Reichstein Nielsen
    <> wrote or quoted :

    >Roedy Green <> writes:
    >
    >> On Mon, 27 Jun 2005 02:02:23 +0200, Lasse Reichstein Nielsen
    >> <> wrote or quoted :
    >>
    >>> 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


    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.

    --
    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, Jun 30, 2005
    #5
  6. Roedy Green

    Roedy Green Guest

    On Thu, 30 Jun 2005 03:05:38 GMT, Roedy Green
    <> wrote or quoted :

    >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);

    }

    }
    }

    --
    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, Jun 30, 2005
    #6
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. -

    enum within an enum

    -, Jun 12, 2005, in forum: Java
    Replies:
    6
    Views:
    564
  2. Jerminia
    Replies:
    3
    Views:
    638
    Roedy Green
    Oct 7, 2005
  3. Ernst Murnleitner

    How to enum an enum?

    Ernst Murnleitner, Nov 12, 2003, in forum: C++
    Replies:
    5
    Views:
    483
    Rolf Magnus
    Nov 13, 2003
  4. mrhicks
    Replies:
    2
    Views:
    439
    Dave Thompson
    Jun 10, 2004
  5. Randy
    Replies:
    1
    Views:
    523
    David Harmon
    Jan 7, 2006
Loading...

Share This Page