Why does JSF null out a nested class successfully instantiated in the backing bean?

人走茶凉 提交于 2020-01-04 06:00:52

问题


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.


回答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.



来源:https://stackoverflow.com/questions/45022342/why-does-jsf-null-out-a-nested-class-successfully-instantiated-in-the-backing-be

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!