1

I have a simple Form in my JSF page that looks as follows:

<html 
  xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://xmlns.jcp.org/jsf/html"
  xmlns:f="http://java.sun.com/jsf/core"
>
  <f:view>
    <h:head>
      <f:metadata>
        <f:viewParam name="cities" value="#{myBean.cities}" />
      </f:metadata>
    </h:head>
    <h:body>
      <h:form>
        <h:messages id="messages" />
        <h:selectManyCheckbox value="#{myBean.cities}" label="Select City" >
          <f:selectItems value="#{myBean.allCities}" />
        </p:selectManyCheckbox>
        <h:commandButton value="Submit">
          <f:ajax execute="@form" render="output"/>
        </h:commandButton>
      </h:form>
      <h:panelGroup id="output">
        Number of Selected Cities: #{myBean.cities.size()}
      </h:panelGroup>
    </h:body>
  </f:view>
</html>

The matching backing bean:

With following bean methods:

@Named
@RequestScoped
public class MyBean {
  private List<String> cities = new ArrayList<>();

  public List<String> getCities() {
    return cities;
  }

  public void setCities(List<String> cities) {
    this.cities = cities;
  }

  public List<String> getAllCities() {
    return new ArrayList<>(Arrays.asList(new String [] {
      "Los Angeles",
      "St. Louis",
      "San Francisco",
      "Dallas",
      }));
  }
}

Observations:

  1. I have added logging to the entry and exit of the getCities and setCities methods. During refresh of the JSF page, the getCities method gets called. However, when submitting, the setCities never gets called.
  2. I do not get any errors or exceptions in the console log (javax.faces.PROJECT_STAGE set to DEVELOPMENT in web.xml).
  3. No errors are being passed to <h:messages/>
  4. set methods do not get called for any form input fields. The page behaves 'odd'.

The issue seems similar to Issue #3 on the accepted answer from commandButton/commandLink/ajax action/listener method not invoked or input value not set/updated, however I do not have an apparent conversion problem for <p:selectCheckboxMenu>. As per documentation it should be able to handle a List<String> perfectly.

So in addition to fixing the obvious problem, how can we make sure any errors related to this are made visible, rather than having this silent type of failure?

YoYo
  • 9,157
  • 8
  • 57
  • 74
  • So **just the presence** of that `f:viewParam` - pointing to the same `Collection` type bean property as an input does - silently prevents user input submission? – Selaron Feb 21 '19 at 07:36
  • Yes. It does not fail at first rendering (when no GET parameters are supplied), but it does fail when submitting (ajax) the form curiously enough. – YoYo Feb 21 '19 at 21:44

1 Answers1

1

In short, <f:viewParam> does not yet support list of values.

The signature of the cities property is List<String>.

Note that when we are trying to pass a parameter for cities (append ?cities=Dallas to the end of the request URL), we suddenly do get an appropriate conversion error in <h:messages/> stating:

Conversion Error setting value 'Dallas' for 'null Converter'.

Also as per referenced posts, we should also include the messages for ajax updates:

    <h:commandButton value="Submit">
      <f:ajax execute="@form" render="output"/>
      <f:ajax execute="@form" render="messages"/>
    </h:commandButton>

When following this, not during first visit, but at least during submit we get an appropriate error:

Conversion Error setting value '[]' for 'null Converter'.

I am not sure why the <f:viewParam>'s need to be set during an ajax-style submit though?

To solve, you can either provide a <f:converter>, or provide additional getter/setters that handles setting/getting the Array or List type based on a String.

Picking a quick solution we can change the <f:viewParam> as follows:

<f:viewParam name="cities" value="#{myBean.citiesCsv}" />

While for the backing bean, we add following method:

  public void setCitiesCsv(String csv) {
    if (csv.isEmpty()) {
      cities = new ArrayList<>();
    } else {
      cities = 
         Stream.of(csv.split(","))
           .collect(Collectors.toCollection(ArrayList<String>::new));
    }
  }

For repeated such efforts, we should probably consider an appropriate converter to be used instead, which we can custom build for simple CSV conversions if it suits our purpose.

Related posts

YoYo
  • 9,157
  • 8
  • 57
  • 74
  • 1
    I have no clue how your extensive answer is an answer to the question. – Kukeltje Feb 20 '19 at 19:19
  • Developers should learn to make a [mcve] and not suspect anything. Suspicion is for conspiracy theorists, not developers. Developers narrow down problems by debugging of which creating an [mcve] is a bigger part. And Sure #3 in https://stackoverflow.com/questions/2118656 would not have helped? – Kukeltje Feb 20 '19 at 20:31
  • I'm not stating it cannot be helpful, it is just that the relation is not that clear. I doubt others that have a sort of similar problem, will read on when they read your question. I think they might stop and think that their problem is unrelated. If you put more emphasis on the 'bigger' thing (not the *whole page* but state that making an [mcve] would be the right approach and begin with stating that the problem is with not decting a conversion error in the viewparam as a short answer and then add a 2nd part with the longer answer it might be helpful. – Kukeltje Feb 20 '19 at 20:35
  • So the answer you referred to (@BalusC wrote more extensive than what I tried, handling many more scenarios) almost got it - problem is this does not apply: "You can use ". Unfortunately for the viewParams, conversion errors do *not* populate the messages (at least what I have observed). Also #3 is on UIInput, not viewParam. lol - I am not a conspiracy theorist. But to all your other points you are right. – YoYo Feb 20 '19 at 20:54
  • 1
    I could be that what you encountered is a complete new case and valid by itself. Good to know the `h:messages` does not help. Then we need to find out in stackoverflow (or another search engine) if there is a way to capture these conversion errors in the viewparam. Tried running in development mode? (like mentioned in the link/answer). And what is your JSF version and implementation? And check https://stackoverflow.com/questions/26755749 helpful to prevent it in the future I'd think. – Kukeltje Feb 20 '19 at 20:57
  • `` will be useful, but it doesn't solve the 'forgot the conversion' problem. For that it needs to be a catch-all, something I can add to the templates all my developers use. But you gave some work and further validation I have to go through. – YoYo Feb 20 '19 at 21:04
  • 1
    I found an answer by me in https://stackoverflow.com/questions/44419951/fviewparam-ignore-wrong-parameters-silently that suggests to try to use @Param annotation from http://showcase.omnifaces.org/cdi/Param. It **can** work with multi valued parameters if done correctly and converters at the same time. Yes, you do not see in the view that it needs a param, but it might be something to look into, since you could use the normal getter/setter than (with some annotations or... – Kukeltje Feb 20 '19 at 22:12
  • Totally different approach, an alternative, but I think this suits really well if it has better out of box support for some conversions. Also I like it better that it moved to the CDI bean, plus I am already using omnifaces. – YoYo Feb 21 '19 at 01:06