1

I am using a Primefaces selectManyCheckbox within an editable Datatable like this one. When the user clicks the edit button, he is able to select between different Documents in the Documents-Column. That is my code. Please note the converter I am using:

<p:dataTable id="tbl" styleClass="fixedLayoutTable no-highlight dblclick-edit edit-commit-others"
            value="#{cc.attrs.manager.mg}" var="mg"
             emptyMessage="#{msgs.noManager}" editable="true" widgetVar="tbl">
        <p:column  headerText="Documents">
            <p:cellEditor>
                <f:facet name="output">
                   <h:outputText value="#{msgs.noDocs}" rendered="#{mg.docs.size() == 0}" />
                <h:outputText value="#{mg.docs.toArray()[0].fileName}" rendered="#{mg.docs.size() > 0}" />
            </f:facet>
                <f:facet name="input">
                    <p:selectManyCheckbox id="chkDoc" 
                            value="#{mg.docs}" layout="pageDirection"
                            converter="myConverter" collectionType="java.util.HashSet">
                        <f:selectItems value="#{cc.attrs.manager.docs}"
                            var="d" itemValue="#{d}" itemLabel="#{d.fileName}" />
                    </p:selectManyCheckbox>
                </f:facet>
            </p:cellEditor>
        </p:column>
    </p:dataTable>

In another Tab of the application (lets call it Tab1) the user is able to upload some Documents. These documents were added to the cc.attrs.manager.docs-List in the backing bean, but won't get persisted in the database yet. If the user uploads some documents in Tab1 and goes to Tab2 (the tab with the datatable), he should be able to select between all documents including the recently added ones. So the user clicks on the edit button, all the documents appear in the SelectManyCheckbox. If the user selects these documents and clicks the ✔-Sign my Converter gets called.

I followed this example to implement the Converter. Here is a Code Snippet of this class:

@FacesConverter(value="myConverter")
public class MyConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        if (component instanceof PickList) {
            return getAsObject((PickList)component, value);
        } else {
            return SelectItemsUtils.findValueByStringConversion(context, component, value, this);
        }
    }
}

This is working fine, until the user doesn't check the recently added documents. If he checks one of the new documents, the String-Parameter of the getAsObject-Method is "null". Does anyone have some suggestions, why this param is null? Is it because the document isn't persisted yet? Is it possible to get this working without persisting the documents added in Tab1?

joshi737
  • 869
  • 3
  • 12
  • 26

2 Answers2

2

Instead of your own custom converter , try this generic converter which will work for everything.

import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.WeakHashMap;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(value = "entityConverter")
public class EntityConverter implements Converter {

    private static Map<Object, String> entities = new WeakHashMap<Object, String>();

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object entity) {
        synchronized (entities) {
            if (!entities.containsKey(entity)) {
                String uuid = UUID.randomUUID().toString();
                entities.put(entity, uuid);
                return uuid;
            } else {
                return entities.get(entity);
            }
        }
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String uuid) {
        for (Entry<Object, String> entry : entities.entrySet()) {
            if (entry.getValue().equals(uuid)) {
                return entry.getKey();
            }
        }
        return null;
    }

}
Makky
  • 17,117
  • 17
  • 63
  • 86
  • Thanks for your reply. I tried your generic converter, but unfortunately the uuid String is still null... – joshi737 Dec 23 '13 at 10:58
  • Then you have some problems in XHTML file . – Makky Dec 23 '13 at 11:02
  • But somehow it is not null for those Documents which were in the table, before some documents were added... – joshi737 Dec 23 '13 at 11:06
  • @joshi737 I can't understand your problem. If you could post your full XHTML and Managed bean I'll try test myself. – Makky Dec 23 '13 at 11:36
  • Sorry, I can't because it is a pretty large and complex application... What is the String-UUID? What is it's value and how gets this value calculated? – joshi737 Dec 23 '13 at 18:50
  • Now I get it. In my case it is the ID of the Entity. According to my question, the recently uploaded documents aren't persisted, so they don't have an ID yet. What can I do in this case? – joshi737 Dec 23 '13 at 18:53
  • How is the ID being generated ? – Makky Dec 23 '13 at 19:37
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/43783/discussion-between-makky-and-joshi737) – Makky Dec 23 '13 at 19:37
1

I solved it by implementing another converter which extends EntityConverter and checks if the ID is null. Thats my code like:

@FacesConverter(value = "anotherConverter")
public class AnotherConverter extends EntityConverter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value instanceof Document && ((Document) value).getId() == null) {
            return String.valueOf(((Document) value).hashCode());
        }
        return super.getAsString(context, component, value);
    }
}
joshi737
  • 869
  • 3
  • 12
  • 26