HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Saving enum value using name()

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
enumvaluenameusingsaving

Problem

Let's assume I have an enum type

enum ComponentState {
    TURNED_OFF,
    TURNED_ON,
    SUSPENDED,
    TO_REPAIR;
}


This enum describes a state of some component. Now let's assume I want to export my component to as XML file. Then, of course, I'm going to import my component. So:

//Export:
componentElement.setAttribute("state", getState.name());  // results in 

//Import
try {
   state = ComponentState.valueOf(element.getAttributeValue("state"));
} catch (IllegalArgumentException e) {
   //... 
}


Everything is fine, but problems starts when I change the name of some enum constants, because it sounds better:

enum ComponentState {
    TURNED_OFF,
    TURNED_ON,
    SLEEPING,   // <- the same sense, but
    CRASHED;    // <- different name (PM's "I want to have")
}


Note, that doing this I'm loosing a backward compatibility.

Question:
How do you cope normally with such situations?

1

public String getXMLValue(){
    // ... implementation independent from name()
}


and

static ComponentState parseXMLString(String s) {
    // ... checking if s matches any name()
}


OR

2

My approach is OK - it should not be expected, that the name on enum will change just because it sounds better.

Solution

I like rolfl's approach, but I have one thing to add which would make it more compact and flexible:

Use a private constructor to provide a custom save value.

The biggest benefits of using either my or rolfl's approach is that you don't need to remember to add new enum values to the HashMap. In my approach especially, it gives you a clear overview of the enum values with their corresponding save values. As long as you only use one constructor (which I highly recommend) it is impossible to forget to give a save value for the enum.

This approach also allows you to customize their save-values much easier. You can rename your enums all you want, all you need to remember is to not change the saveValue, unless you want incompatibility issues.

enum ComponentState {
    TURNED_OFF("off"),
    TURNED_ON("on"),
    SUSPENDED("susp"),
    TO_REPAIR("repair");

    private final String saveValue;

    private ComponentState(String saveAs) {
        this.saveValue = saveAs;
    }

    private static final Map FUZZY = buildMap();

    private static Map buildMap() {
        Map mapto = new HashMap<>();
        for (ComponentState state : ComponentState.values()) {
            mapto.put(state.saveValue, state);
        }
        return mapto;
    }

    private static final ComponentState fuzzyValueOf(String name) {
        return FUZZY.get(name);
    }

    public String getSaveValue() {
        return this.saveValue;
    }
}


If you want to have multiple possible save values for the same enum, then use a String... parameter: (However, in this case you need to make sure that you don't use an empty constructor for a field, as that wouldn't give it a specified save value)

private final String[] saveValues;
    private ComponentState(String... saveAs) {
        this.saveValues = saveAs;
    }
    public String getSaveValue() {
        return this.saveValues[0];
    }


I really can't recommend using the .ordinal approach as ratchet freak suggested, even though it is nice and tidy, consider this enum:

Suit {
    DIAMONDS, HEARTS, SPADES, CLUBS;
}


Now what if you'd like to re-order them?

Suit {
    CLUBS, SPADES, DIAMONDS, HEARTS;
}


Congratulations, spades has become diamonds, clubs is hearts. Down is up and up is down. Logic goes on ski vacation with it's buddy reason.

If you use the .ordinal approach, remember to never ever ever switch places of them. (Me, talking from experience? What makes you think that?)

Code Snippets

enum ComponentState {
    TURNED_OFF("off"),
    TURNED_ON("on"),
    SUSPENDED("susp"),
    TO_REPAIR("repair");

    private final String saveValue;

    private ComponentState(String saveAs) {
        this.saveValue = saveAs;
    }

    private static final Map<String, ComponentState> FUZZY = buildMap();

    private static Map<String, ComponentState> buildMap() {
        Map<String, ComponentState> mapto = new HashMap<>();
        for (ComponentState state : ComponentState.values()) {
            mapto.put(state.saveValue, state);
        }
        return mapto;
    }

    private static final ComponentState fuzzyValueOf(String name) {
        return FUZZY.get(name);
    }

    public String getSaveValue() {
        return this.saveValue;
    }
}
private final String[] saveValues;
    private ComponentState(String... saveAs) {
        this.saveValues = saveAs;
    }
    public String getSaveValue() {
        return this.saveValues[0];
    }
Suit {
    DIAMONDS, HEARTS, SPADES, CLUBS;
}
Suit {
    CLUBS, SPADES, DIAMONDS, HEARTS;
}

Context

StackExchange Code Review Q#45317, answer score: 6

Revisions (0)

No revisions yet.