enum aliases

R

Roedy Green

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
 
L

Lasse Reichstein Nielsen

Roedy Green said:
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;
}
}
 
R

Roedy Green

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 (e-mail address removed)
*/

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
 
L

Lasse Reichstein Nielsen

Roedy Green said:
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
 
R

Roedy Green

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


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
 
R

Roedy Green

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top