8

Is there any proper way to override the way JSF accesses the beans fields from an Expression Language? The idea is to mimic this behavior in order to access a Map<String, ?> values, where the bean fields would be the map keys.

In other words, is it possible anyhow to use #{beanContainingNestedMap.keyOfSaidNestedMap}, just as if keyOfSaidNestedMap were a field of the beanContainingNestedMap?

If not, what other solution may I have?


Example:

Holder.java

public class Holder {

    private Map<String, Object> objects = new HashMap<String, Object>();

    public void add(String key, Object value) {
        objects.put(key, value);
    }

    public Object getObject(String key) {
        return objects.get(key);
    }

}

ExampleBean.java

public class ExampleBean {

    private Holder holder = new Holder();

    public ExampleBean() {
        holder.add("foo", 42);
        holder.add("bar", 'X');
    }

    public Holder getHolder() {
        return holder;
    }

}

example.xhtml

<c:out value="#{exampleBean.holder.foo}" /> <!-- should print "42" -->
<c:out value="#{exampleBean.holder.bar}" /> <!-- should print "X" -->

What would be great is if I could do something like (kind of pseudo-code since I don't know if such a method exists ;)):

@Override // override JSF's (if any...)
public Object resolveEl(String el) {
    try {
        super.resolveEl(el);
    } catch (ElException e) {
        Object bean = e.getBean();
        String fieldName = e.getFieldName();
        if (bean instanceof Holder) {
            Holder holder = (Holder) bean;
            Object value = holder.getObject(fieldName);
            if (value == null) {
                throw e;
            } else {
                return value;
            }
        }
    }
}
sp00m
  • 47,968
  • 31
  • 142
  • 252
  • This problem is not about JSF but EL. There's a map access section in the [StackOverflow EL wiki](http://stackoverflow.com/tags/el/info). To cite two examples: `${someMap[dynamicKey]}`, `${some['class'].simpleName}` – Luiggi Mendoza Jul 26 '13 at 14:37
  • @LuiggiMendoza Thank you for the tips, but the idea was first to know if it is possible anyhow to use `#{beanContainingAMap.keyOfTheSaidMap}` instead, just as if `keyOfTheSaidMap` were a field of the bean. – sp00m Jul 26 '13 at 14:42
  • If you check the link provided in my comment, you will see that's currently not possible. You have to use `#{exampleBean.holder[foo]}`. – Luiggi Mendoza Jul 26 '13 at 14:43
  • @LuiggiMendoza It must be technically feasable anyhow, am I wrong? I'll wait a little bit to see other potential answers. But don't hesitate to add your own, since if you have the only right answer, I'll willingly accept it `;)` – sp00m Jul 26 '13 at 14:47
  • Your question is confusing. EL already supports maps out the box using exactly the same syntax as javabeans. – BalusC Jul 26 '13 at 14:47
  • @BalusC Please have a look at my second comment to get more precisions. – sp00m Jul 26 '13 at 14:49
  • I'm not sure why you want to do it the harder way if a simple way already exist. – BalusC Jul 26 '13 at 14:53

2 Answers2

18

You can directly use map by EL.

Holder.java

public class Holder {

    private Map<String, Object> objects = new HashMap<String, Object>();

    public void add(String key, Object value) {
        objects.put(key, value);
    }

    public Map<String, Object> getObjectsMap() {
        return objects;
    }

}

EL

#{exampleBean.holder.objectsMap[your-key]}
Zaw Than oo
  • 9,651
  • 13
  • 83
  • 131
-1

This problem is not about JSF but EL. As noted in @BalusC comment, you can directly use the notation you already want/need with Map objects. I've prepared a basic example on this (note: this is just an example and should remain as is or improved since it uses scriptlets and we must avoid scriptlets usage but made it for a quick dirty test):

<%@page import="edu.home.model.entity.User"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
    <%
        //Scriptlets usage, sorry. This code must be moved to a Servlet or another controller component
        //defining the map
        Map<String, User> aMap = new HashMap<String, User>();
        //defining a value for the map
        User user = new User();
        user.setFirstName("Luiggi");
        user.setLastName("Mendoza");
        //adding the value in the map 
        aMap.put("userLM", user);
        //making the map accesible in EL through PageContext attribute
        pageContext.setAttribute("aMap", aMap);
    %>
    <!-- Accessing directly to the userLM key and its attributes -->
    ${aMap.userLM.firstName} - ${aMap.userLM.lastName}
</body>
</html>

User class code (minimized for test purposes):

public class User {
    private String firstName;
    private String lastName;
    //empty constructor
    //getters and setters
}

This generates a JSP page that prints:

Luiggi - Mendoza

Note that this (except the scriptlet part) will work on a Facelets page as well since this is EL and not JSF.

Community
  • 1
  • 1
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332