JSF, EL, Managed Beans - How to tell what the getter & setter signatures are?
Asked Answered
G

1

8

With JSF, Managed Beans, & EL 2.2 I know generally that an expression of the form:

#{bean.value}

Will map to a corresponding set of functions in a managed bean class like so:

@ManagedBean
class Bean {
    private String value;
    public String getValue() { return value; }
    public void setValue( String s ) { value = s; }
}

It is also possible to get and set properties of a map:

#{bean.value['key']}

Backed by something like:

@ManagedBean
class Bean {
    private Map<String, Boolean> kvMap;
    public boolean getValue( String key ) { return kvMap.get( key ); }
    public void setValue( String key, boolean value ) { kvMap.put( key, value ); }
}

So far so good.

I'm finding as I spend more time with JSF however that I'm trying to write reusable chunks of code. Specifically, small blocks of xhtml in <ui:composition> blocks that I can include via <ui:include>. What's more, many of the more useful things for me are things like nested sets of checkboxes (our UI designer is just gaga over them ;-), and there <ui:repeat> becomes very handy.

Invariably, in order to use <ui:repeat> and <ui:include> without an ungodly amount of typing, I've been using aliases, either created via <ui:param> or inline with something like the var attribute of <ui:repeat>.

As I've been writing more and more nested UIComponents, particularly things that get their values from maps within maps, I'm finding it harder and harder to deduce the correct setter method signature that JSF will look for when submitting a form (for some reason writing getters seems to be more natural).

My question for you gurus then is:

Is there some way to get JSF to tell me what it expects a setter signature to look like? Since JSF generally doesn't complain about an expression that resolves to a getter-only (thinking it is a read-only property), I find the lack of feedback frustrating and it seems to require a lot of fiddling with different method signatures before I finally hit that magic right one.

I'm hoping there's some technique, say a FacesContext... query at runtime or looking in some compiled intermediate like a class file that would point me to the correct setter signature for a deeply nested property. If there is such a thing I think it would save me a lot of time trying to figure out how to get a setter constructed by trial and error.

Hopefully I've articulated clearly enough what I'm after, thanks in advance for your replies.

Germinative answered 15/5, 2012 at 6:30 Comment(3)
+1 for an excellent question... I think what you and I both want is something like the Eclipse Debugging Perspective Display window except for ad-hoc JSF and EL expressions. If we cannot find this then it sounds like a wicked cool project for an open source Eclipse plugin!Trusteeship
After posting this question I spent some time (re)reading the EL 2.2 spec and it does seem like there are excellent facilities in the ELResolver and its counterparts to create some nice tools. However since seeing clearly that JSF is having no trouble setting values in Map expressions, no matter how ugly they seem to be (e.g. #{blah.foo[name]['x'][otherThing]}) I don't know if it's worth the time. Thanks for the +1 though :)Germinative
getValue( String key ), setValue( String key, boolean value ) - I don't think this works. Java Beans 1.01 do specify indexed properties, but the keys must 'int's.Maelstrom
L
8

I understand that your question basically boils down to "How should a setter for a Map look like?".

The answer is simple: you don't need any one. EL uses the put() method on the Map itself. You only need to provide a getter for the whole Map. On getting map values, EL will use the get() method of the Map itself. This is all behind the scenes done by the builtin MapELResolver.

So this should do:

@ManagedBean
class Bean {
    private Map<String, Boolean> kvMap;
    public Map<String, Boolean> getValue() { return kvMap; }
}

which is to be used as #{bean.value['key']} or #{bean.value.key} if the key doesn't contain periods. You can just use it in input components as well.

<h:selectBooleanCheckbox value="#{bean.value.key}" />

As to the tooling, well, the JBoss Tools plugin for Eclipse has good EL autocomplete support for normal javabeans, but it can't autocomplete map keys. Further Eclipse has its own facilities to autogenerate bean properties along with getters and setters based on a list or existing properties.

Linlithgow answered 15/5, 2012 at 13:7 Comment(1)
Thanks BalusC, and sadly you're right, my question does ultimately boil down to how to deal with setting values on maps, which you've already addressed in several posts & comments on SO. I had a very complex aliased EL expression that grabbed a map deep within some other data structures and JSF was setting its values properly. I had a bug in another routine that was masking the fact that it was doing its job properly. :( I ultimately subclassed HashMap and overrode put() to convince myself that JSF was setting the values properly, which led to finding my bug. Thanks again!Germinative

© 2022 - 2024 — McMap. All rights reserved.