2

For the sake of clarity (and brevity) I am listing just the key segments of my code.

I have a backing bean MemberView containing two nested classes:

private Person person;
private Member member;

that are instantiated when the page loads:

@PostConstruct
public void init() {
    person = new Person();
    member = new Member();
}

with the appropriate getters and setters. I have a web page, member.xhtml, that utilizes PrimeFaces and displays nested class properties:

<p:inputText value="#{memberView.person.lastName}" />
<p:inputText value="#{memberView.member.id}" />

and a CommandButton that calls a search routine in the backing bean:

<p:commandButton value="Retrieve" type="submit" 
                      actionListener="#{memberView.fetchMembers()}" 
                      update="@all"/>

The page loads without incident. But selecting the CommandButton results in an EL ContextAwarePropertyNotFoundException: javax.el.PropertyNotFoundException: Target Unreachable, 'member' returned null.

To track what is happening, I added some logging to the get- and setMember methods:

public Member getMember() {
    LOG.info("getMember() invoked");
    if(member == null) {
        LOG.log(Level.WARNING, "getMember() returning NULL");
    }
    LOG.info("getMember() returning Member: " + member.toString()
            + " with ID: " + member.getId());
    return member;
}

public void setMember(Member member) {
    LOG.info("setMember() invoked with argument: " + member);
    this.member = member;
}

Here is the output when I click on the CommandButton:

INFO: getMember() invoked
INFO: getMember() returning Member: scc.model.Member@6f453701 with ID: null
INFO: getMember() invoked
INFO: getMember() returning Member: scc.model.Member@6f453701 with ID: null
INFO: getMember() invoked
INFO: getMember() returning Member: scc.model.Member@6f453701 with ID: null
INFO: setMember() invoked with argument: null
INFO: getMember() invoked
WARNING: getMember() returning NULL

Clearly, the class Member is being nulled out. One further detail. If I comment out the member ID input field

<!-- <p:inputText value="#{memberView.member.id}" /> -->

and then select the Retrieve button, the page populates a dataTable with the names of members and the name field, as supplied by the nested MemberView Person class:

<p:dataTable id="dtPerson" var="member"
            style="margin-top:10px;text-align:center;width:400px;minWidth:400px"
                     value="#{memberView.selectableMemberList}"
                     selectionMode="single" editable="false"
                     selection="#{memberView.member}" >

<p:inputText value="#{memberView.person.lastName}" />

I am at a complete loss to explain the EL call to the setMember method with a null argument after three calls that successfully returned the instantiated class. I am open to any and all suggestions.

halfer
  • 19,824
  • 17
  • 99
  • 186
Robert Peake
  • 118
  • 8
  • 2
    You're setting the `` on very same property. Is this intented? If nothing's selected or the provided selection doesn't match any record in datatable, consequences speak for itself. – BalusC Jul 10 '17 at 22:15
  • Does this mean that the dataTable sets memberView.member to null even though no selection has been made and no selection event has been fired? My selection listener logs all such events. I have numerous other web pages where dataTable selection is set to clazzView.clazz and inputText fields on the same form are set to clazzView.clazz.variable and these work just fine. So to answer your question, yes, this is intentional. I can understand a class variable being set to null, but not the class itself. – Robert Peake Jul 10 '17 at 23:14
  • Yes it does since the datatable cannot know how an 'empty/new/initialized' member object is treated by you. Being null is more explicit. The getters are called in different phase of the jsf 'submission cycle' See http://balusc.omnifaces.org/2011/09/communication-in-jsf-20.html. You could work around what you experience, but it would be a...well... workaround. Better to not use the same property like BalusC stated – Kukeltje Jul 11 '17 at 06:27
  • It can happen if dataTable is processed in same submit. You can confirm this by looking at XHR payload or by putting a breakpoint in setter and inspecting the call stack who invoked it and why. – BalusC Jul 11 '17 at 09:56

1 Answers1

1

Thanks to you both for your timely and helpful responses. Following BalusC's suggestion, a trace shows that the Method class is nulled during DataTable.processUpdates. Since there is no row data, and therefore no Member to be found in the table, the PrimeFaces SelectableDataModel returns null, which is then set by the JSF method BeanELResolver.setValue.

My prior databases all utilize many-to-one relationships where ArrayLists are populated on post-construct and, by design, are never empty thereafter. One possible resolution here would be to populate the data table when the page loads, as suggested in this 2006 post by BalusC ("You can load the dataList in either the constructor or initialization block of the [backing] bean.") http://balusc.omnifaces.org/2006/06/using-datatables.html

A more general solution is to provide the data table with a blank, not empty, data list, both on initialization and whenever a query returns an empty result set:

/**
* Member edited/displayed in web page text fields 
*/
private Member member;

/**
 * List of Member Objects
 */ 
private List<Member> mList;

/**
 *  Member List implementing PF SelectableDataModel
 */
private SelectableMemberList selectableMemberList;

/**
 * Creates a blank [not empty] SelectableMemberList.
 * Call on PostConstruct & on return of empty result set.
 */
private void blankSelectableMemberList() {
    if(mList == null) {         // instantiate on init()
        mList = new ArrayList<>();
    }
    if(mList.isEmpty()) {       // add blank Object
        mList.add(new Member());
    }
selectableMemberList = new SelectableMemberList(mList);
}

I hope this is helpful to anyone who wants to display an "empty" data table.

Robert Peake
  • 118
  • 8
  • This is a 'complex' workaround. Better to look for how the `process` attribute on a `commdButton` can be used to limit not 'processing' the datatable selection. https://stackoverflow.com/questions/25339056/understanding-primefaces-process-update-and-jsf-fajax-execute-render-attributes – Kukeltje Jul 14 '17 at 05:44
  • Complexity is a matter of perspective. I am comfortable with my Java-based solution because I understand it and find it simple to implement, while the information contained in your link is difficult to decipher. Plus, I prefer to keep null-checking in the code, where it belongs, rather than intermingling it with the view (MVC). Further, and this may simply reflect my own limitations, I don't know how to restrict processing of the data table to whether or not a query returns a null result set, if doable. Finally, nulls are anathema to the programmer and I prefer to keep them out of my code. – Robert Peake Jul 22 '17 at 19:17
  • If the information in the link I posted is hard to decipher, I am afraid you will run into many related issues, (partly) fixing them in workarounds and in the end 'blame' JSF for being complex... Better to really try to understand the information in the link. It is important! And I never said to do null checks in the view btw... – Kukeltje Jul 24 '17 at 10:10