Primefaces Datatable converter with filtering - jsf

I have the datatable and selectonemenu inside it.
I want to show images in select one menu items.So a have Rating class and converter ratingConverter for Rating class.
I have the next problem here: filtering by this column works just once! When I try to change item, method load(..) from LazyComicsDataModel calls. But after
filtering one time nothing worked! Method load not calls anymore. There are't any exceptions in server.log. When I don't use converter and class Rating (use just String class) it works right any number of times.
I would like to get any ideas why it might be happened.
Code:
Part of xhtml page:
<p:ajax
event="rowSelect"
update=":form:comicsDetail"
oncomplete="PF('comicsDialog').show()"/>
<p:column width="20%"
headerText="#{comicsCatalogueView.columnComicsRating}"
sortBy="#{comics.rating}"
filterBy="#{comics.rating}"
filterMatchMode="exact" >
<f:facet name="filter" >
<p:selectOneMenu
value="#{comicsCatalogueView.rating}"
var="r"
onchange="PF('comicsTable').filter()"
converter="ratingConverter"
>
<f:selectItem
value="#{null}"
itemValue="#{null}" />
<f:selectItems
value="#{comicsFinderManagedBean.ratings}"
var="rating"
itemLabel="#{rating.value} - #{rating.value+1}"
itemValue="#{rating}"
/>
<p:column>
<p:graphicImage value="#{r.image}"/>
</p:column>
</p:selectOneMenu>
</f:facet>
<h:panelGroup>
<pf:rating disabled="true"
totalStars="5"
step="0.1"
value="#{comics.rating}"
>
</pf:rating>
</h:panelGroup>
</p:column>
Rating class:
public class Rating {
public Rating(Integer value, String image) {
this.value = value;
this.image = image;
}
private Integer value;
private String image;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
#Override
public int hashCode() {
int hash = 5;
hash = 71 * hash + (this.value != null ? this.value.hashCode() : 0);
hash = 71 * hash + (this.image != null ? this.image.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Rating other = (Rating) obj;
if (this.value != other.value && (this.value == null || !this.value.equals(other.value))) {
return false;
}
if ((this.image == null) ? (other.image != null) : !this.image.equals(other.image)) {
return false;
}
return true;
}
#Override
public String toString() {
return "Rating{" + "value=" + value + ", image=" + image + '}';
}
Rating converter:
#FacesConverter("ratingConverter")
public class RatingConverter implements Converter {
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
ComicsFinderManagedBean ratingFinderManagedBean = (ComicsFinderManagedBean)
fc.getExternalContext().getApplicationMap().get("comicsFinderManagedBean");
return ratingFinderManagedBean.getRating(Integer.parseInt(value));
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null) {
return String.valueOf(((Rating) object).getValue());
}
else {
return null;
}
}
}

Related

Get composite component inputs' converted values

I have a composite component made of two p:calendars:
<cc:interface componentType="testComponent">
<cc:attribute name="value" type="org.primefaces.test.DateRange" />
</cc:interface>
<cc:implementation>
<c:set value="dd-MM-yyyy" var="pattern" />
<p:panelGrid columns="2">
<p:outputLabel for="from" value="From" />
<p:calendar id="from" binding="#{cc.from}" pattern="#{pattern}" />
<p:outputLabel for="to" value="To" />
<p:calendar id="to" binding="#{cc.to}" pattern="#{pattern}" />
</p:panelGrid>
</cc:implementation>
Class DateRange:
public class DateRange {
private Date from;
private Date to;
public DateRange() {
}
public DateRange(Date from, Date to) {
this.from = from;
this.to = to;
}
public Date getFrom() {
return from;
}
public void setFrom(Date from) {
this.from = from;
}
public Date getTo() {
return to;
}
public void setTo(Date to) {
this.to = to;
}
#Override
public String toString() {
return from + " --> " + to;
}
}
Backing class:
#FacesComponent("testComponent")
public class TestComponent extends UIInput implements NamingContainer {
private UIInput from;
private UIInput to;
private static final String DELIMITER = "-->";
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
DateRange range = (DateRange) getValue();
System.out.println(range);
if (range != null) {
from.setValue(range.getFrom());
to.setValue(range.getTo());
}
super.encodeBegin(context);
}
#Override
public Object getSubmittedValue() {
if (from == null || to == null) return null;
String submittedFrom = (String) from.getSubmittedValue();
String submittedTo = (String) to.getSubmittedValue();
if (submittedFrom == null) {
submittedFrom = "";
}
if (submittedTo == null) {
submittedTo = "";
}
return submittedFrom + DELIMITER + submittedTo;
}
#Override
protected Object getConvertedValue(FacesContext context, Object newSubmittedValue) throws ConverterException {
String submitted = (String) newSubmittedValue;
if (submitted == null || submitted.isEmpty()) {
return null;
}
String[] split = submitted.split(DELIMITER);
String fromStr = split.length > 0 ? split[0] : "";
String toStr = split.length > 1 ? split[1] : "";
// TODO: Do I need to perform a manual conversion of the inputs???
return new DateRange((Date) fromObj, (Date) toObj);
}
getConvertedValue() should return an instance of DateRange. To get dates from calendars, I would need to call getConvertedValue() on each but this method is protected and I cannot access it.
Do I need to manually get the pattern from the p:calendar and convert the value myself? If yes, how do I even know how the conversion is really done in Calendaritself? I wonder how is this approached in more complex components where conversion on subcomponents is not that trivial.

Display list of images using p:graphicImage in p:dataGrid after uploading image through p:fileUpload

i am uploading multiple images through p:fileUpload and showing uploaded images in datagrid but after upload the blank panel is created inside datagrid
<p:panelGrid columns="1" layout="grid" style="width: 1000px">
<p:outputLabel value="Upload Images"></p:outputLabel>
<p:fileUpload mode="advanced" multiple="false"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/" dragDropSupport="true"
update="messages,updimgsfields,carouselcomp" sizeLimit="100000"
fileUploadListener="#{drawingattachmnt.handleFileUpload}"></p:fileUpload>
<!-- <p:graphicImage id="gimPhoto" value="#{fileuploadSection.image}" /> -->
</p:panelGrid>
<p:fieldset id="updimgsfields" legend="Uploaded Images">
<p:dataGrid id="updimgsdatagrid" var="upldimg"
value="#{drawingattachmnt.uploadedimages}" columns="4">
<p:panel id="drawingattachmntpnl" header="#{upldimg.displayId}"
style="text-align:center">
<h:panelGrid columns="1" cellpadding="5"
style="width: 100%; height: 200px;">
<p:graphicImage value="#{upldimg.imgcontent}" cache="false"
stream="true">
<f:param id="imgId" name="photo_id" value="#{upldimg.id}" />
</p:graphicImage>
</h:panelGrid>
</p:panel>
<p:draggable for="drawingattachmntpnl" revert="true"
handle=".ui-panel-titlebar" stack=".ui-panel" />
</p:dataGrid>
</p:fieldset>
// file upload function inside bean
public void handleFileUpload(final FileUploadEvent event) throws IOException {
if (event.getFile().getContents() != null) {
final ByteArrayOutputStream byteArrOutputStream = new ByteArrayOutputStream();
BufferedImage uploadedImage = null;
byte[] imageBytes = null;
try {
final String imageType = event.getFile().getContentType() != null
|| event.getFile().getContentType().split("/") != null ? event.getFile().getContentType()
.split("/")[1] : "jpeg";
uploadedImage = ImageIO.read(event.getFile().getInputstream());
ImageIO.write(uploadedImage, imageType, byteArrOutputStream);
imageBytes = byteArrOutputStream.toByteArray();
updimg.setImgcontent(new DefaultStreamedContent(new ByteArrayInputStream(imageBytes), imageType));
updimg.setId(UUID.randomUUID().toString().substring(0, 8));
updimg.setDisplayId("FIG: ");
uploadedimages.add(updimg);
} catch (final IOException io) {
} finally {
try {
byteArrOutputStream.close();
// imageInputStream.close();
} catch (final IOException e1) {
e1.printStackTrace();
}
uploadedImage.flush();
}
final FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(null, new FacesMessage("Successful", "File uploaded Successfully "));
}
// List POJO
import org.primefaces.model.StreamedContent;
public class UploadImage {
public String displayId;
public String id;
public StreamedContent imgcontent;
public UploadImage() {
}
public UploadImage(final String id, final String displayId, final StreamedContent imgcontent) {
this.id = id;
this.displayId = displayId;
this.imgcontent = imgcontent;
}
#Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final UploadImage other = (UploadImage) obj;
if (this.id == null ? other.id != null : !this.id.equals(other.id)) {
return false;
}
return true;
}
public String getDisplayId() {
return displayId;
}
public String getId() {
return id;
}
public StreamedContent getImgcontent() {
return imgcontent;
}
#Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + (this.id != null ? this.id.hashCode() : 0);
return hash;
}
public void setDisplayId(final String displayId) {
this.displayId = displayId;
}
public void setId(final String id) {
this.id = id;
}
public void setImgcontent(final StreamedContent imgcontent) {
this.imgcontent = imgcontent;
}
}
I need to show images in datagrid dynamically, but i am getting blank image panel inside datagrid. what should be done ?

PrimeFaces auto complete return a null object

this is my xhtml page
<h:form id="order_search" prependId="flase">
<p:growl id="growl" showDetail="true" autoUpdate="true"
sticky="false" />
<h:panelGrid columns="5" style="margin-bottom:10px" cellpadding="5">
<p:outputLabel value="Customer Name : " for="ac_order" />
<p:autoComplete id="ac_order" value="#{orderSearchController.orderFromAutoC}"
completeMethod="#{orderSearchController.autoCompleteOrder}" var="order"
itemLabel="#{order.customerName}" itemValue="#{order}"
converter="#{orderConverter}" forceSelection="true" />
<p:commandButton id="selected" value="print" action="#{orderSearchController.printOrder}" />
</h:panelGrid>
</h:form>
and this is my backing bean
#Component
#ManagedBean
#ViewScoped
public class OrderSearchController implements Serializable{
private static final long serialVersionUID = 1L;
#ManagedProperty(value = "#{orderService}")
public OrderService orderService;
public List<Order> allOrders;
public List<Order> acFilterdOrders;
public Order orderFromAutoC;
#PostConstruct
public void Init() {
System.out.println("init gets called");
// allOrders = new ArrayList<>();
// orderFromAutoC = new Order();
allOrders = orderService.getAllOrders();
System.out.println("After sssssss ");
}
public List<Order> autoCompleteOrder(String query) {
acFilterdOrders = new ArrayList<Order>();
for (int i = 0; i < allOrders.size(); i++) {
if (allOrders.get(i).getCustomerName().toLowerCase().startsWith(query)) {
acFilterdOrders.add(allOrders.get(i));
}
}
return acFilterdOrders;
}
public String printOrder() {
System.out.println("Inside print");
System.out.println("Inside print : "+orderFromAutoC);
return null;
}
//Getters and Setters
}
and this is my converter code
#ManagedBean(name = "orderConverter")
#RequestScoped
public class OrderConverter implements Converter {
#ManagedProperty(value = "#{orderService}")
private OrderService orderService;
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) {
if (value != null && value.trim().length() > 0) {
return orderService.getOrderById(Integer.parseInt(value));
} else {
return null;
}
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
// TODO Auto-generated method stub
return null;
}
public OrderService getOrderService() {
return orderService;
}
public void setOrderService(OrderService orderService) {
this.orderService = orderService;
}
}
the auto-complete component works fine but but when i tried to get the selected value from it in the backing bean it always return a null
The getAsString method is not implemented correctly as it is just returning the NULL value. The return value of getAsString method is passed as value in the getAsObject method based on which it get the value from the list. Here is an example for your reference . Value in the getAsObject method is the Id that is returned from getAsString method.
#Override
public Object getAsObject(FacesContext fc, UIComponent uic, String value) {
if(value != null && value.trim().length() > 0) {
MessageLogBean messageLogBean = (MessageLogBean) SessionUtility.getManagedBean("messageLogBean");
DeviceResponseDTO deviceResponseDTO = new DeviceResponseDTO();
deviceResponseDTO.setId(Integer.parseInt(value));
List<DeviceResponseDTO> deviceResponseDTOs = messageLogBean.getDeviceResponseDTOs();
int index = deviceResponseDTOs.indexOf(deviceResponseDTO);
if(null != deviceResponseDTOs && !deviceResponseDTOs.isEmpty()){
return deviceResponseDTOs.get(index);
}
return null;
}
else {
return null;
}
}
#Override
public String getAsString(FacesContext fc, UIComponent uic, Object object) {
if(object != null) {
return String.valueOf(((DeviceResponseDTO) object).getId());
}
else {
return null;
}
}

JSF Converter Validation Error: Value not valid

I have a rich:pickList, when submit values it still displays error: "Validation Error: Value is not valid". I also set breakpoint to debug (getAsobject), but after system invocation I had nothing.
BalusC said that I would implement the equals() method in my entities, or I have the entities in the web service, and I fill the right side of the picklist with data from this web service.
xHTML file
<h:form>
<rich:panel>
<h:panelGrid columns="2" styleClass="criteresSaisie"
rowClasses="critereLigne" columnClasses="titreColonne,">
<h:outputLabel for="libelleComplement" value=" "
size="20" />
<rich:pickList id="libelleComplement" sourceCaption="Compléments"
targetCaption="Compléments sélectionnés"
value="#{listeCmpltDispoModel.listeCmpltSelect}" size="15"
addText=">" addAllText=">>" removeText="<"
removeAllText="<<" listWidth="270px" listHeight="110px"
orderable="true">
<f:selectItems value="#{listeCmpltDispoModel.listeCmpltDispo}"
var="liste" itemLabel="#{liste.libelleComplement}"
itemValue="#{liste}" />
<f:converter converterId="cmpltsTitresConcerter" />
</rich:pickList>
</h:panelGrid>
<h:panelGroup>
<div align="right">
<h:panelGrid columns="8">
<h:commandButton value="Valider"
action="#{saisieCmpltsTitreCtrl.valider}" />
</h:panelGrid>
</div>
</h:panelGroup>
</rich:panel>
</h:form>
Converter
#FacesConverter(value="cmpltsTitresConcerter")
public class CmpltsTitresConcerter implements Converter
{
public Object getAsObject(FacesContext context, UIComponent component, String value)
{
ComplementsDispoSortieDTO cmpltSelect= new ComplementsDispoSortieDTO();
if(value != null)
{
cmpltSelect.setCdComplement(Long.parseLong(value));
//cmpltSelect.setLibelleComplement("aaa");
}
return cmpltSelect;
}
public String getAsString(FacesContext arg0, UIComponent arg1, Object obj)
{
String result = null;
if(obj != null)
{
result = String.valueOf(((ComplementsDispoSortieDTO) obj).getCdComplement());
}
return result;
}
}
Model
#ManagedBean(name = "listeCmpltDispoModel")
#SessionScoped
public class ListeCmpltDispoModel implements Serializable {
private static final long serialVersionUID = 1L;
private Long cdComplement;
private String libelleComplement;
private int nbCompl;
private List<ComplementsDispoSortieDTO> listeCmpltDispo ;
private List<ComplementsDispoSortieDTO> listeCmpltSelect ;
public ListeCmpltDispoModel() {
}
public Long getCodeComplement() {
return cdComplement;
}
public void setCodeComplement(Long cdComplement) {
this.cdComplement = cdComplement;
}
public String getLibelleComplement1() {
return libelleComplement;
}
public void setLibelleComplement1(String libelleCoplement) {
this.libelleComplement = libelleCoplement;
}
public Long getCdComplement() {
return cdComplement;
}
public void setCdComplement(Long cdComplement) {
this.cdComplement = cdComplement;
}
public String getLibelleComplement() {
return libelleComplement;
}
public void setLibelleComplement(String libelleComplement) {
this.libelleComplement = libelleComplement;
}
public List<ComplementsDispoSortieDTO> getListeCmpltDispo() {
return listeCmpltDispo;
}
public void setListeCmpltDispo(List<ComplementsDispoSortieDTO> listeCmpltDispo) {
this.listeCmpltDispo = listeCmpltDispo;
}
public int getNbCompl() {
return nbCompl;
}
public void setNbCompl(int nbCompl) {
this.nbCompl = nbCompl;
}
public List<ComplementsDispoSortieDTO> getListeCmpltSelect() {
return listeCmpltSelect;
}
public void setListeCmpltSelect(List<ComplementsDispoSortieDTO> listeCmpltSelect) {
this.listeCmpltSelect = listeCmpltSelect;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((cdComplement == null) ? 0 : cdComplement.hashCode());
result = prime
* result
+ ((libelleComplement == null) ? 0 : libelleComplement
.hashCode());
result = prime * result
+ ((listeCmpltDispo == null) ? 0 : listeCmpltDispo.hashCode());
result = prime
* result
+ ((listeCmpltSelect == null) ? 0 : listeCmpltSelect.hashCode());
result = prime * result + nbCompl;
return result;
}
#Override
public boolean equals(Object obj){
if(!(obj instanceof ComplementsDispoSortieDTO)){
return false;
}
return ((ComplementsDispoSortieDTO)obj).getCdComplement()==this.cdComplement;
}
}
The equals() method of your entity is not right. It's not only in the wrong class (the backing bean class instead of the model class), but it's also using == on an Object (the == on an object only tests the reference, not the internal value; as a starter, you should have experienced this mistake on String values already).
The == on a Long would only return true is the Long instance was created by Long#valueOf() or Long#parseLong() and the value is between -128 and 127. Anything else, including new Long(value) and those with values beyond the given "flyweight" range, return false.
As with every other Java object (such as your current one), you need equals() instead. Put it in the right class and implement it as follows:
public class ComplementsDispoSortieDTO {
private Long cdComplement;
// ...
#Override
public boolean equals(Object obj){
if (!(obj instanceof ComplementsDispoSortieDTO)){
return false;
}
return (cdComplement != null)
? cdComplement.equals(((ComplementsDispoSortieDTO) obj).cdComplement)
: (obj == this);
}
}
Note that I also added the missing reflexive obj == this. See also the javadoc for list of requirements.
See also:
Validation Error: Value is not valid
Right way to implement equals contract
I know which could be the solution.
You should store the list and selected element in properties and maintain them in the scope as long as the component is used.

Primefaces PickList target is empty on ajax transfer listener

I have the following p:pickList:
<p:pickList id="activityUser" value="#{activityEntryController.activityUserDualListModel}" var="model" itemLabel="#{model.fullName}"
itemValue="#{model}" converter="activityUserListConverter" styleClass="activityUser" required="true" showSourceFilter="true"
showTargetFilter="true" filterMatchMode="contains">
<f:facet name="sourceCaption">Available</f:facet>
<f:facet name="targetCaption">Selected</f:facet>
<p:column style="width: 400px">
<h:outputText value="#{model.fullName}" />
</p:column>
<p:ajax event="transfer" listener="#{activityEntryController.sortUsersOnTransfer}" update="activityUser" />
</p:pickList>
The value of this p:pickList is a class which extends the DualListModel<T>:
public class ActivityUserDualListModel extends DualListModel<ActivityUserDTO> {
private static final long serialVersionUID = -5369543532197736480L;
public ActivityUserDualListModel() {
super();
initModel();
}
public ActivityUserDualListModel(List<ActivityUserDTO> source, List<ActivityUserDTO> target) {
super(source, target);
initModel();
}
private void initModel() {
IServiceProvider serviceProvider = (IServiceProvider) ContextLoader.getCurrentWebApplicationContext().getBean(Beans.SERVICE_PROVIDER.getName());
IUserService userService = serviceProvider.getUserService();
List<ActivityUserDTO> activityUserDTOs = new ArrayList<ActivityUserDTO>();
for(User user : userService.getAllUser()) {
if(user.isActive()) {
activityUserDTOs.add(constructActivityUserDTO(user));
}
}
Collections.sort(activityUserDTOs, ComparatorUtils.getActivityUserFullNameComparator());
setSource(activityUserDTOs);
setTarget(new ArrayList<ActivityUserDTO>());
}
private ActivityUserDTO constructActivityUserDTO(User user) {
ActivityUserDTO activityUserDTO = new ActivityUserDTO();
activityUserDTO.setId(user.getId());
activityUserDTO.setUsername(user.getUsername());
activityUserDTO.setFullName(user.getFullName());
return activityUserDTO;
}
}
I am instantiation the ActivityUserDualListModel from the PostConstruct method of the ActivityEntryController managed bean.
The listener of the p:ajax which fires at the time of event transfer is:
public void sortUsersOnTransfer(TransferEvent event) {
List<ActivityUserDTO> source = activityUserDualListModel.getSource();
List<ActivityUserDTO> target = activityUserDualListModel.getTarget();
System.out.println("=============================================");
for(ActivityUserDTO dto : source) {
System.out.println(dto.getFullName());
}
System.out.println("=============================================");
System.out.println("=============================================");
for(ActivityUserDTO dto : target) {
System.out.println(dto.getFullName());
}
System.out.println("=============================================");
if(source != null) {
Collections.sort(source, ComparatorUtils.getActivityUserFullNameComparator());
}
if(target != null) {
Collections.sort(target, ComparatorUtils.getActivityUserFullNameComparator());
}
}
The strange thing is the target list in the above method is empty. I am unable to find what I am missing. Any pointer would be very helpful to me.
Edit:
The following class is the converter:
#FacesConverter("activityUserListConverter")
public class ActivityUserListConverter implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (!(component instanceof PickList)) {
return null;
}
if (StringUtils.isBlank(submittedValue)) {
return null;
}
#SuppressWarnings("unchecked")
DualListModel<ActivityUserDTO> pickListModel = (DualListModel<ActivityUserDTO>) ((PickList) component).getValue();
ActivityUserDTO ret = null;
for (ActivityUserDTO activityUserDTO : pickListModel.getSource()) {
if (activityUserDTO.getId().equals(Long.parseLong(submittedValue))) {
ret = activityUserDTO;
break;
}
}
if (ret == null) {
for (ActivityUserDTO activityUserDTO : pickListModel.getTarget()) {
if (activityUserDTO.getId().equals(Long.parseLong(submittedValue))) {
ret = activityUserDTO;
break;
}
}
}
return ret;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null || value.equals("")) {
return "";
}
if (value instanceof ActivityUserDTO) {
return String.valueOf(((ActivityUserDTO) value).getId());
}
return "";
}
}
Also I have the following p:commandButton for submitting the form. Now the actionListener is not firing, but it fires if I remove the p:pickList form the xhtml.

Resources