java.lang.Character comparison in EL - jsf

I've a java.lang.Character bean property which I'd like to compare in EL as below:
#{q.isMultiple eq 'Y'}
It does not ever evaluate true.
How is this caused and how can I solve it?

In contrary to "plain Java", whether you single or double-quote your literals in EL, they represent both java.lang.String instances. Your method is returning a java.lang.Character instance, so this will never return true in an equals() call between both instances.
The solution is to change it to a String or boolean return type. The property name isMultiple strongly suggests a boolean. You only need to remove that is from the property name and keep it in the getter method.
private boolean multiple;
public boolean isMultiple() {
return multiple;
}
#{q.multiple}
An alternative is using an enum. This would only be applicable if you have more than two states (or perhaps three, a Boolean also includes null).

Can also do this by converting the Character to String by printing it as body of <c:set> as below:
<c:set var="isMultipleVal">#{q.isMultiple}</c:set>
And then comparing it instead:
#{isMultipleVal eq 'Y'}

If you're using EL 2.2, one workaround is:
#{q.isMultiple.toString() eq 'Y'}

You may need to look the property isMultiple in the Class of variable 'q'. Please verify your class having a getter method with signature as public char getIsMultiple(){}.
Also, are you sure ${q.isMultiple eq 'Y'} gives true?

Related

Value of selectManyCheckBox of type Calendar being cast as String [duplicate]

I am using <p:selectCheckboxMenu> on a List<Long>:
<p:selectCheckboxMenu value="#{bean.selectedItems}">
<f:selectItems value="#{bean.availableItems}" />
</p:selectCheckboxMenu>
private List<Long> selectedItems;
private Map<String, Long> availableItems;
When submitting the form and looping over the selected items as below,
for (int i = 0; i < selectedItems.size(); i++) {
Long id = selectedItems.get(i);
// ...
}
Then I get a class cast exception:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Long
at com.example.Bean.submit(Bean.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.el.parser.AstValue.invoke(AstValue.java:278)
at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:274)
at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:87)
... 27 more
The same problem occurs with <p:selectManyCheckbox>, <p:selectManyMenu>, <h:selectManyMenu>, etc. All multiple-selection components basically. It works fine in <p:selectOneMenu> and all other single-selection components on a single value Long property.
How is this caused and how can I solve it?
Your problem is caused by the following facts:
Java generics are compiletime syntactic sugar and completely absent during runtime.
EL expressions runs during runtime and not during compiletime.
HTTP request parameters are obtained as Strings.
Logical consequence is: EL doesn't see any generic type information. EL doesn't see a List<Long>, but a List. So, when you don't explicitly specify a converter, EL will after obtaining the submitted value as String set it unmodified in the List by reflection means. When you attempt to cast it to Long afterwards during runtime, you'll obviously face a ClassCastException.
The solution is simple: explicitly specify a converter for String to Long. You can use the JSF builtin LongConverter for this which has the converter ID javax.faces.Long. Other builtin converters are listed here.
<p:selectCheckboxMenu ... converter="javax.faces.Long">
Another solution without the need to explicitly specify the converter is to change List<T> type to a T[]. This way the EL will see the Long typed array and thus perform automatic conversion. But this possibly requires changes elsewhere in the model which may not be desirable.
private Long[] selectedItems;
In case you're using a complex object (javabean, entity, POJO, etc) as select item value instead of a standard type like Long for which JSF has builtin converters, then the same rules also apply. You only need to create a custom Converter and explicitly specify it in input component's converter attribute, or rely on forClass if you can use T[]. How to create such a converter is elaborated in Conversion Error setting value for 'null Converter'.

concatenation of Strings in EL

I want to display name (current user) in a drop down list in JSF. Here name is a dynamic variable that gets populated though some pojo class. The present code that I have is
<f:selectItem itemLabel="#{accessManager.salesManager.displayName} #{' ('.concat(i.m['current user']).concat(') ')}" itemValue="#{accessManager.salesManager.oid}" />
accessManager.salesManager.displayName populates the name on the UI.
#{' ('.concat(i.m['current user']).concat(') ')}" here I am trying to hard code (current user).
But this is throwing exceptions.
Can any one help me in this? It sounds to be a very simple query but I am not used to EL.
Based on your example, the easiest way is to provide an extra function in your managed bean which evaluates if the current user is the current choice or not. Later on, you evaluate that function with a ternary operator, which will decide wether to display the bundled (translated) value or not.
#ViewScoped
public class ChoiceBean{
public List<SalesManager> getSalesManagers(){
return salesManagers;
}
//Checks if your current choice is the current manager(EL 2.2 required to pass the parameter)
public boolean checkIfCurrent(SalesManager manager){
if (manager.getName().equals("Bob")) return true;
return false;
}
}
<f:selectItem
itemLabel="#{manager.name} #{choiceBean.checkIfCurrent(manager) ? i.m['current user'] : ''}" itemValue="#{salesManager.oid}" />
See also:
Passing parameter to JSF action
Ternary operator in JSTL/EL
Another solution is to use a function doing this String concatenation for you. Either
you use the JSTL functions library with fn:join (see enter link description here) or
implement your own static method in EL, and use that one. The method itself would (surprisingly) look like
public static String concat(String string1, String string2) {
return string1.concat(string2);
}
and the call in JSF, nested like #{fn:concat('(',fn:concat(i.m['current user'],')'))}.
But, out of curiosity, why don't you want to add the brackets into the properties file, so the ressource-value holds (current user) instead of current user?
Hope it helps...
So the question is how do I concat '(' & ')' before and after #{i.m['current user'])}
Don't do it the hard way. Just put those parentheses outside the EL expression.
<f:selectItem itemLabel="#{accessManager.salesManager.displayName} (#{i.m['current user']})" itemValue="#{accessManager.salesManager.oid}" />

Is this a bug in primefaces autocomplete?

I'm trying to put an autocomplete that fetches suggestions as a list of Entry<String, Integer>
<p:autoComplete completeMethod="#{suggester.suggestTopics}"
var="x1" itemLabel="#{x1.key}" itemValue="#{x1.value.toString()}"
value="#{topicController.selected}" />
Manged bean code is as follows:
private int selected;
public int getSelected() {
return selected;
}
public void setSelected(int selected) {
this.selected= selected;
}
But this fails saying the Integer class doesn't have method/property named key. If I remove the value attribute from autocomplete then it starts working properly. But when I put value attribute it starts expecting that the object inside var should be of the same type as that inside value attribute. I believe/expect it should be that the object inside itemValue should be of the same type as that inside value attribute.
I want to use POJOs for suggestions but pass just the entity Id to the value
Using :
Primefaces 3.1
JSF 2.1.6
I believe/expect it should be that the object inside itemValue should
be of the same type as that inside value attribute.
Yes this makes sense, and it is the same in the primefaces showcase:
<p:autoComplete value="#{autoCompleteBean.selectedPlayer1}"
id="basicPojo"
completeMethod="#{autoCompleteBean.completePlayer}"
var="p" itemLabel="#{p.name}" itemValue="#{p}"
converter="player" forceSelection="true"/>
As you see is var="p" and itemValue="#{p} where p is an instance of Player. And selectedPlayer1 is also an instance of Player.
I don't know if it works with a Map since the Primefaces example is called "Pojo support" and the suggestions should be a List of elements of the same type as in the value attribute.
I think you want to use the Simple auto complete , but instead you looked at the wrong example on the showcase of the Pojo Support
x1 refers to the int selected - while it expect to be referred to a POJO (with key and value properties.) , that's why you get the message
Integer class doesn't have method/property named key
Or simple use the Simple auto complete
As commented to Matt you dont need to rebuild Player(Pojo) from Db. You can set simply id property of Player(Pojo) and in action method may be utilize this id to fetch it from DB.
In your case in convertor you might do
Entry<String, Integer> e = new Entry<String, Integer>();
e.setId(value) // where value is passed in to convertor in method getAsObject.....
This value will be set to private Entry<String, Integer> selected
I have used Pojo autocomplete but not tried with generic classes.
Hope this helps.
I know the question is outdated but I've had the same problem.
The point is that you have to assign var to p (var="p"). I think it's terribly unobvious (documentation doesnot mention it has to be that way) 'cause I thought I can assign any var name I want.

"ValueExpression Map" of a JSF component

I'm storing value expressions in a JSF component with the f:attribute tag, e.g.:
<h:inputText ...>
<f:attribute name="myId1" value="#{bean.prop1}" />
<f:attribute name="myId2" value="#{bean.prop2}" />
<f:attribute name="myId3" value="#{bean.prop3}" />
</h:inputText>
Is there a way to access all of those value expressions programmatically? (without knowlegde of the names myId1, myId2,...)
Section 9.4.2 of the JSF 2.1 specification says that those values are stored "in the component’s ValueExpression Map".
That's the only occurrence of the term "ValueExpression Map" in the complete spec.
How do I access that map?
In the UIcomponent's Method getValueExpression() of the Jboss/Mojarra implementation the map
getStateHelper().get(UIComponentBase.PropertyKeys.bindings)
is used to obtain a single value expression.
I guess that map is a super set of the "ValueExpression Map"?
Can I be sure that all implementations and all inherited (standard) components use that map to store ValueExpressions?
Thanks.
In theory you should be able to see them all by UIComponent#getAttributes():
Map<String, Object> attributes = component.getAttributes();
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
System.out.printf("name=%s, value=%s%n", entry.getKey(), entry.getValue());
}
However, that doesn't work the way as you'd expect. It only returns static attributes. This does not seem to ever going to be fixed/implemented. See also JSF issue 636. I'd suggest to stick to attribtues with predefinied prefix and an incremental numerical suffix, like as you've presented in your example. That's also what I've always used to pass additional information from the component on to custom validators and converters. You can just collect them as follows:
Map<String, Object> attributes = component.getAttributes();
List<Object> values = new ArrayList<Object>();
for (int i = 1; i < Integer.MAX_VALUE; i++) {
Object value = attributes.get("myId" + i);
if (value == null) break;
values.add(value);
}
System.out.println(values);
An alternative to the answer given by BalusC might be to use nested facets or UIParameter components. Facets can be retrieved as a map using getFacets but you probably need to put an additional UIOutput inside each facet to access its value expression.
Nested UIParameters can be accessed by iterating over the components children and checking for instanceof UIParameter. UIParameters have name and value attributes and so could be easily converted to a map.
I have used parameters in a custom component, but I'm not sure how a standard UIInput like in your example reacts to these.
BalusC is right. UIComponent#getAttributes().get(name) gets values from both places - at first from attributes map and then if not found from "value expression map". To put some value you have to call UIComponent#setValueExpression(name, ValueExpression). If value is literal, it gets stored into the attribute map, otherwise into the "value expression map". Everything is ok then.

how to access a EL variable and pass it as an argument to a function in EL?

I want to call a function on a bean with an argument passsed to it in jsp using EL.
The problem is it does not allow something like:
"${teacherBean.certificationFor(${particularField})"
the thing is i want to iterate over an array and call the function certificationFor for all the values in the array passed as an argument.
I am getting the values in array by:
So Basically i want to do something like:
${teacherBean.certificationFor(${particularField})
but i cant do that.
can i do this in any other way?
I am a newbie in EL . :)
Any help is appreciated.
Where exactly do you want to do that and for what? Just to get a value for display? At least, in standard EL prior to Java EE 6 you cannot pass method arguments like that. In JBoss-EL or in Java EE 6 EL you can do that. The syntax would then just have been:
${teacherBean.certificationFor(particularField)}
Note that you cannot nest EL expressions, an EL expression is already a whole expression at its own.
In standard EL implementations you can however access Map values by keys using the brace notation. Thus, if you for example have a Map<String, String> certifications where the keys corresponds the particularField and the values the associated value:
private Map<String, String> certifications = new HashMap<String, String>();
public Map<String, String> getCertificationFor() {
return this.certifications;
}
then you can use the following notation:
${teacherBean.certificationFor[particularField]}
this resolves behind the scenes to
teacherBean.getCertificationFor().get(particularField)
I think in the standard EL you don't have any options other than defining your functions wrapped in a EL function;
Read: http://java.sun.com/j2ee/1.4/docs/tutorial/doc/JSPIntro7.html near the bottom of the
document;
but as BalusC mentioned already if you could use another EL implmentation if you have the ability to add that kind of dependency to your app
What about:
${teacherBean.certificationFor(particularField)}
If you are accessing a general functionality that is better expressed as a separate function, then you can write it as follows:
${certificationFor[teacherBean][particularField]}
where certificationFor maps to the CertificationFor class which extends ELMethod.java class. You implement the functionality in the result(Object[] args) method. The args to this method are the args that you passed to the ${certificationFor} object in EL.
public class CertificationFor extends ELMethod {
public Object result(Object[] args) {
TeacherBean teacherBean = (TeacherBean) args[0];
String property = (String) args[1];
// your implementation goes here
return ....;
}
}
The trick is to use your object as a chained map of maps, that is one way to pass multiple args to EL function.
If you are interested, you can see full code and code snippets here:
http://www.vineetmanohar.com/2010/07/how-to-pass-parameters-in-el-methods/

Resources