简体   繁体   中英

Trying to bind a multi-value field to a managed Java bean in XPages

I have developed a simply 'Configuration' custom control that has several fields bound to a managed Java bean. It all works really well, except for the multi-value field. That works fine IF I provide more than one value in the field. If I only supply ONE value, it fails.

The Java bean contains...

private Vector<String> acctTypes;

... and the getters/setters...

public void setAcctTypes ( Vector<String> content ) {this.acctTypes = content;} 
public Vector<String> getAcctTypes() {return acctTypes;}

In the custom control, I bind the field to the bean...

<xp:inputText id="inputAcctTypes" title="Account Types" value="#{config.acctTypes}"
multipleTrim="true" multipleSeparator=";">
</xp:inputText>

That totally fails if a single value is entered into the field. I tried making it a textarea as well, with no success...

<xp:inputTextarea id="inputAcctTypes" title="Account Types"
value="#{config.acctTypes}" rows="5" multipleTrim="true">
<xp:this.multipleSeparator><![CDATA[#{javascript:"\n"}]]></xp:this.multipleSeparator>
</xp:inputTextarea>

Forgive my ignorance... I know that XPages returns a string value when a single value is entered in a multi-value field, but for the life of me I can't figure out how to accommodate for that when binding to a managed bean.

Can anyone tell me where I'm going wrong here?

Doh!

I've been searching for ages for a solution, and THEN happened on this excellent post from Tommy that explains the technique right after posting my question...

http://dontpanic82.blogspot.com.au/2012/06/multi-value-fields-and-beans-in-xpages.html

Hope this helps someone else that finds themselves in a similar bind. I changed my getters/setters...

public void setNotifications ( Object content ) {this.notifications = translateToVector(content);} 
public Object getNotifications() {return notifications;}

... and then added the necessary translation function...

private Vector<String> translateToVector( Object object ){
    if( object instanceof String ){
             Vector<String> list = new Vector<String>();
             list.add( (String) object );
             return list;
         }

         if( object instanceof List ){
             return (Vector<String>)object;
         }
         return null;
}

Use a converter:

<xp:inputText id="inputText1" value="#{config.acctTypes}">
    <xp:this.converter>
        <xp:convertList delimiter=";" />
    </xp:this.converter>
</xp:inputText>

The converter provided by the framework is not "perfect", in the sense that it will convert an input empty value to a 1 value List where that value is "". From a certain perspective it makes sense but it might not be what you want. Otherwise you can extend or create your own converter in order to get what you want.

This approach is best practice . You want your controller to receive the "treated" value instead of changing your method param to an all-you-can-eat object and then attempt to parse it accordingly. As much as it's possible the bean should be agnostic regarding how the data was converted from the POST phase. You achieve that with converters, that's their job.

The benefits are several: you have cleaner code and you can get (use) the value elsewhere without having to cast it (suppressing warnings in the case of lists) any time you need it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM