I am having trouble in using a JSF composite-component in the right way. I put some components together and everything was working. Then I just extracted the code to a composite-component, and passed the corresponding attributes and suddenly I am getting conversation exceptions.
<composite:interface>
<composite:attribute name="selectedIDs" type="java.util.Collection" required="true"/>
<composite:attribute name="selectItems" type="java.util.List" required="true" />
<composite:attribute name="addAction" required="true"/>
<composite:attribute name="deleteAction" required="true"/>
<composite:attribute name="deleteButtonDisabled" />
<composite:attribute name="ajaxListener" method-signature="void listener(javax.faces.event.AjaxBehaviorEvent)"/>
</composite:interface>
<composite:implementation>
<div class="myClass">
<h:outputStylesheet library="views" name="selectManyControlPanel.css" target="head" />
<h:form>
<h:selectManyListbox value="#{cc.attrs.selectedIDs}">
<f:selectItems value="#{cc.attrs.selectItems}" />
<f:ajax render="delete"
listener="#{cc.attrs.ajaxListener}" />
</h:selectManyListbox>
<br />
<h:commandButton id="delete" value="Delete"
disabled="#{cc.attrs.deleteButtonDisabled}"
action="#{cc.attrs.deleteAction}" />
<h:commandButton id="add" value="Add" action="#{cc.attrs.addAction}"/>
</h:form>
</div>
</composite:implementation>
Here is the page where I am using the newly created component
<view:selectManyControlPanel
selectedIDs="#{bean.selectedIds}"
selectItems="#{bean.listOfSelectItems}"
addAction="#{bean.addNew}"
deleteAction="#{bean.deleteSelection}"
ajaxListener="#{bean.selectionChanged}"
deleteButtonDisabled="#{bean.deleteButtonDisabled}" />
Bean (some methods skipped an parts renamed)
package views;
@SuppressWarnings("serial")
@Named
@RequestScoped
public class Bean implements Serializable, IOverviewView {
@Inject
Presenter presenter;
private boolean deleteButtonDisabled;
private List<SelectItem> listOfSelectItems;
private Set<Long> selectedIds;
public Bean(){
deleteButtonDisabled = true;
listOfSelectItems = new ArrayList<SelectItem>(10);
}
public void selectionChanged(AjaxBehaviorEvent event){
if(selectedIds.isEmpty())
deleteButtonDisabled = true;
else
deleteButtonDisabled = false;
}
public void deleteBikes(){
presenter.delete(selectedIds);
}
public void addNew(){
presenter.addNew();
}
public List<SelectItem> getListOfSelectItems() {
return listOfSelectItems;
}
public Set<Long> getSelectedIds() {
return selectedIds;
}
@PostConstruct
public void init(){
System.out.println("INITIALIZING BEAN: " + this.getClass().getName());
this.presenter.setView(this);
this.presenter.init();
}
public boolean isDeleteButtonDisabled() {
return deleteButtonDisabled;
}
@Override
public void setDeleteButtonEnabled(boolean isEnabled) {
deleteButtonDisabled = !isEnabled;
}
public void setListOfSelectItems(List<SelectItem> list) {
this.listOfSelectItems = list;
}
public void setSelectedIds(Set<Long> selectedIds) {
this.selectedIds = selectedIds;
}
@Override
public void updateBikesList(Set<ViewObject> objectsToDisplay) {
updateList(objectsToDisplay);
}
private void updateList(Set<ViewObject> objectsToDisplay){
listOfSelectItems.clear();
for (ViewObject vO : objectsToDisplay) {
final String label = vO.getManufacturer() + ", " + vO.getModel() + " (" + vO.getYear() + ")";
listOfSelectItems.add(new SelectItem(vO.getId(), label));
}
}
....
}
Exception
javax.el.ELException: /resources/views/selectManyControlPanel.xhtml @25,56 value="#{cc.attrs.selectedIDs}": /index.xhtml @21,70 selectedIDs="#{bean.selectedIds}": Cannot convert [Ljava.lang.String;@1e92093 of type class [Ljava.lang.String; to interface java.util.Set
The only thing that changed is that I am using the composition instead of the plain code. The EL-expressions are still the same. Can someone enlighten me please? I expected that the parameters are just passed through but obviously not...
This is related to Mojarra issue 2047. It's scheduled to be fixed in the upcoming 2.2.
The issue ticket also proposes the following workaround:
<view:selectManyControlPanel
selectedIDsBean="#{bean}"
selectedIDsProperty="selectedIds"
with in CC interface
<composite:attribute name="selectedIDsBean" required="true"/>
<composite:attribute name="selectedIDsProperty" required="true"/>
and in CC implementation
<h:selectManyListbox value="#{cc.attrs.selectedIDsBean[cc.attrs.selectedIDsProperty]}">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With