0

I have a EnumMap:

EnumMap<Gender, Integer> genderMap = new EnumMap(Gender.class);

where Gender is public enum Gender {Male, Female};

And I have req.setAttribute("genderMap", genderMap);

Now I want to get the value from genderMap by a key in JSP file:

${genderMap['Male']}

but this doesn't get the value in genderMap. Why?

jmj
  • 237,923
  • 42
  • 401
  • 438
bayinamy
  • 487
  • 4
  • 14

4 Answers4

0

My solution was to create a wrapper (adapter) for enum maps. It expects String keys and converts them to corresponding Enum values by calling Enum.valueOf() method.

Relevant parts from an example bean:

private Map <Action, Permission> permissions = new EnumMap<>(Action.class);

/** For java access */
public Map<Action, Permission> getPermissions() {
    return permissions;
}

/** For EL access */
public Map<String, Permission> getPermissionsAsString() {
    return new EnumMapWrapper<>(Action.class, permissions);
}

Now I can conveniently access the map elements in EL:

#{rule.permissionsAsString['MODIFY']}

Here's the wrapper class:

public class EnumMapWrapper<K extends String, V> implements Map<K, V> {

    private Map<Enum, V> map;
    private Class<? extends Enum> enumType;

    public EnumMapWrapper(Class<? extends Enum> enumType, Map<? extends Enum, V> map) {
        this.enumType = enumType;
        this.map = (Map<Enum, V>)map;
    }

    private Enum valueOf(Object key) {
        if (!(key instanceof String)) {
            throw new IllegalArgumentException("Only string keys are permitted");
        }

        return Enum.valueOf(enumType, (String)key);
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean containsKey(Object key) {
        return map.containsKey(valueOf(key));
    }

    @Override
    public boolean containsValue(Object value) {
        return map.containsValue(value);
    }

    @Override
    public V get(Object key) {
        return map.get(valueOf(key));
    }

    @Override
    public V put(K key, V value) {
        return map.put(valueOf(key), value);
    }

    @Override
    public V remove(Object key) {
        return map.remove(valueOf(key));
    }

    @Override
    public void putAll(Map<? extends K, ? extends V> m) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void clear() {
        map.clear();
    }

    @Override
    public Set<K> keySet() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Collection<V> values() {
        return map.values();
    }

    @Override
    public Set<Entry<K, V>> entrySet() {
        throw new UnsupportedOperationException();
    }
}
tuner
  • 326
  • 3
  • 9
0
Map<Gender, Integer> genderMap = new HashMap<Gender, Integer>();

and

${genderMap['Male']}

this would work definitely.

jmj
  • 237,923
  • 42
  • 401
  • 438
  • 2
    Err, no. HashMap is not a subclass of EnumMap, and 'Male' evaluates to a String, not a Gender. – JB Nizet Aug 03 '11 at 08:43
  • `Male` would evaluted to ENUM , See :http://stackoverflow.com/questions/123598/access-enum-value-using-el-with-jstl – jmj Aug 03 '11 at 08:46
  • 2
    No. In the top answer of the question you linked to, the solution consists in comparing strings together. someModel.status is converted to a string and compared to the string 'OLD'. And my point regarding HashMap and EnumMap still stands. – JB Nizet Aug 03 '11 at 08:49
  • Type mismatch: cannot convert from HashMap to EnumMap – bayinamy Aug 04 '11 at 02:59
0

Because 'Male' evaluates to the String "Male", not to Gender.Male. You would need to have access to the Gender.Male constant to access its map entry. But accessing constants is not possible in JSP EL, so you might want to do :

req.setAttribute("male", Gender.Male);
req.setAttribute("genderMap", genderMap);

...

${genderMap[male]}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • What if the enum 'Gender' has a hundred values, do I have to "req.setAttribute("some enum value" Gender.someValue)" a hundred time? – bayinamy Aug 04 '11 at 03:03
  • You could put all these values in a single bean, or you could step back a little and ask yourself if accessing hundreds of specific values in a JSP is normal, and shouldn't be encapsulated somehow in some piece of Java code. – JB Nizet Aug 04 '11 at 06:57
  • As to setting it hundred times, you have the same problem when using a `Map`. You would call `put()` hundred times as well. – BalusC Aug 04 '11 at 13:27
0

Don't use enum mappings. Just use enums as enums in Java and as strings in JSP/EL.

I'll assume that you need that integer because of a database mapping. E.g. Male is stored as 1 in database and Female is stored as 0 in database. In that case, you need to redesign your enum as follows:

public enum Gender {

    Male(1), Female(0);

    private int id;

    private Gender(int id) { 
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public static Gender valueOf(int id) {
        for (Gender gender : values()) {
            if (gender.id == id) {
                return gender;
            }
        }

        return null;
    }

}

When populating the Person from DB by JDBC, just do

person.setGender(Gender.valueOf(resultSet.getInt("gender")));

When showing preselected options to enduser in JSP, just do

request.setAttribute("genders", Gender.values());

and

Gender:<br/>
<c:forEach items="${genders}" var="gender">
    <input type="radio" id="gender_${gender.id}" name="gender" value="${gender.id}" 
        ${gender == person.gender ? 'checked="checked"' : ''} />
    <label for="gender_${gender.id}">${gender}</label>
    <br />
</c:forEach>

or even without the id

Gender:<br/>
<c:forEach items="${genders}" var="gender">
    <input type="radio" id="gender_${gender}" name="gender" value="${gender}" 
        ${gender == person.gender ? 'checked="checked"' : ''} />
    <label for="gender_${gender}">${gender}</label>
    <br />
</c:forEach>

When collecting submitted values in servlet, just do

Gender gender = Gender.valueOf(Integer.valueOf(request.getParameter("gender")));

or when using without id in HTML

Gender gender = Gender.valueOf(request.getParameter("gender"));
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • OK, thx for the answer. My solution is Using a new Map: HashMap genderMap, where Key(String) is Gender.name(). So I can use genderMap['Male'] to get the value in jsp. – bayinamy Aug 29 '11 at 07:25
  • Hate to downvote, but the answer doesnt really address the question. – Stefan Oct 27 '12 at 16:14