0

I have a @SessionScoped bean that I would like to use as a map so that I can dynamically get its properties using EL in the view.

myBean['someDynamicProperty']

I have achieved this by implementing java.util.Map, implementing get(Object o) with my application logic and throwing an UnsupportedOperationException in all other overriden Map methods.

@SessionScoped
@Named
public class MyBean implements Map<String, String> {

    @Override
    public String get(Object key) {
        // Application logic here
    }

    @Override
    public boolean containsKey(Object key) {
        throw new UnsupportedOperationException();
    }

    // All other map methods overriden like containsKey
}

The properties are read only and I only need to use the get method from my code, but is it safe not to implement the other Map methods?

Is there a better way to define dynamic properties for EL in a bean?

maxmil
  • 390
  • 1
  • 12

1 Answers1

2

It would be better to store the map as a session attribute, so you won't need to create the @SessionScoped bean and it could be accessed through expression language without problems.

public void methodThatShouldCreateTheMap() {
    //declaring the variable as myBean for compatibility with your current code
    Map<String, Object> myBean = new HashMap<String, Object>();
    //fill myBean here...
    //...
    //store myBean in session
    FacesContext.getCurrentInstance()
        .getExternalContext()
        .getSession(false)
        .setAttribute("myBean", myBean);
}

You may access to the map directly in EL:

${myBean['key']}

From comments:

The issue is that my bean is not really a Map. In the get method I implement the logic I require based on the key that I receive. (...) In my case the business logic in the getter is not costly.

Seems that in some way you would need your bean to implement Map interface. Instead reinventing the wheel or marking the methods to throw UnsupportedOperationException, extend from a class that already implements all the methods, like HashMap or LinkedHashMap, or a class that implements Map but doesn't implement it at all, like AbstractMap, and left empty the other methods:

@Named
@SessionScoped
public class MyBean extends AbstractMap<String, Object> {
    @Override
    public Object get(String key) {
        //add your logic here...
    }
    @Override
    public void set(String key, Object value) {
        //do nothing...
    }
    //similar for other unnecessary methods...
}
Luiggi Mendoza
  • 85,076
  • 16
  • 154
  • 332
  • I achieve this by annotating my bean with @Named. However this is does not answer the question. The issue is that my bean is not really a Map. In the get method I implement the logic I require based on the key that i receive. – maxmil Apr 28 '14 at 21:02
  • 1
    @maxmil I can infer that your bean extends from `Map` or something similar. I'm proposing this solution since I assumed your getter doesn't have any business logic. Be aware of [getter methods being called multiple times](http://stackoverflow.com/q/2090033/1065197). – Luiggi Mendoza Apr 28 '14 at 21:05
  • Multiple calls to getter methods is a good consideration although in my case the business logic in the getter is not costly. – maxmil Apr 28 '14 at 21:09
  • You surely wanted your code to say `extends AbstractMap`? – mabi Apr 28 '14 at 21:20
  • If i extend AbstractMap i need to at least implement entrySet(). I would really prefer not to since calculating all the properties of my bean could be costly. I'm really just trying to get the syntactic sugar that Map gives me in EL from a bean that is not a Map at all. I'm beginning to think that my use of the Map interface is not a good idea. – maxmil Apr 28 '14 at 21:35
  • @maxmil again, you don't have to do it. But if that's still a high costly problem for you, extend from `HashMap` directly and store nothing in the underlying collection. – Luiggi Mendoza Apr 28 '14 at 21:36
  • Implementing entrySet to return an empty set or extending HashMap would mean that some UnsupportedOperationExceptions would not be thrown. I think that i would prefer to know about it if some code is trying to use my bean as a fully implemented map. – maxmil Apr 28 '14 at 21:48
  • But you're right, extending AbstractSet and implementing entrySet to throw an UnsupportedOperation would clean up my code. – maxmil Apr 28 '14 at 21:53