title: JSF Cross Composite Component Validation
body: <p>I have a "composit component" daymonth for selecting a day and a month (comp:daymonth):</p>
  
  <pre><code>&lt;ui:composition ... &gt;
      &lt;cc:interface&gt;
          &lt;cc:attribute name="value" type="model.DayMonth" required="true" /&gt;    
          &lt;cc:editableValueHolder name="forMonth" targets="selected_month" /&gt;
              ...
  &lt;/cc:interface&gt;            
  
  &lt;cc:implementation&gt;
      &lt;p:selectOneMenu id="selected_month" value="#{cc.attrs.value.monthAsString}"&gt;
          &lt;f:selectItems value="#{cc.attrs.value.months}"/&gt;
      &lt;/p:selectOneMenu&gt;
  ...
  &lt;/cc:implementation&gt;
  
  &lt;/ui:composition&gt;
  </code></pre>
  
  <p>The using page looks something like:</p>
  
  <pre><code>&lt;h:form id="form"&gt;
       ...
          &lt;comp:daymonth id="von" value="#{controller.von}"&gt;
            &lt;/comp:daymonth&gt;
          &lt;comp:daymonth id="bis"    value="#{controller.bis}"&gt;
              &lt;f:validator binding="#{vonBisValidator}" for="forMonth"/&gt;
          &lt;/comp:daymonth&gt;
      ...
  &lt;/h:form&gt;        
  </code></pre>
  
  <p>I want to validate the month of "von" with the month of "bis" (eg. "bis".selected_month greater than "von".selected_month). </p>
  
  <p>The Validator looks like:</p>
  
  <pre><code>@Named("vonBisValidator")
  @ApplicationScoped
  public class vonBisValidator implements Validator, Serializable {
      @Override
      public void validate(final FacesContext context, final UIComponent component, final Object value) throws ValidatorException {
  
      // Just to show what ist going on, the real implementation would check the values against each other, sets invalid and throws exception etc.    
      try {
          final UIViewRoot viewRoot = context.getViewRoot();
  
          final SelectOneMenu gueltigVon = (SelectOneMenu) viewRoot.findComponent("form:von:selected_month");
          final SelectOneMenu gueltigBis = (SelectOneMenu) viewRoot.findComponent("form:bis:selected_month");
  
          final Object vonValue = gueltigVon.getValue();
          final Object bisValue = gueltigBis.getValue();
  
          final Object bisValueS = gueltigBis.getSubmittedValue();
          final Object vonValueS = gueltigVon.getSubmittedValue();
  
          System.out.println("vonValue : " + vonValue + "\t bisValue :" + bisValue);
          System.out.println("vonValueS: " + vonValueS + "\t bisValueS:" + bisValueS);
  
      } catch (final Exception ex) {
          System.out.println(ex);
      }}
  </code></pre>
  
  <p>On Screen "von: März bis: Oktober" is shown, as expected from database reading.
  When I select another "bis" eg. Januar, the System.out is:</p>
  
  <pre><code>vonValue : Oktober     bisValue :Oktober
  vonValueS: null     bisValueS:Januar
  
  Why ist vonValue of von-Component Oktober? Should it not be März?
  </code></pre>
  
  <p>After that I select another "bis" eg. Februar, the System.out is:</p>
  
  <pre><code>vonValue : Januar bisValue :Januar
  vonValueS: null     bisValueS:Februar
  
  Why ist vonValue of von-Component Januar?
  </code></pre>
  
  <p>Debugger results: </p>
  
  <ul>
  <li>The gueltigVon has an other java-id then gueltigBis. The correct Components are found.</li>
  <li>The ComponentStateHelper-ids of von and bis are different.</li>
  <li>The component.getFacesContext().getELContext() for EL retrieval is always the same.</li>
  <li>For gueltigVon.getValue();: As the submitted value for "von" hasn't changed, localValue is not set and the getValue(..) falls back to the super.gerValue(..) (javax.faces.component.ComponentStateHelper). There, because get(key) returns null, the value ist read by EL with/from the component.getFacesContext().getELContext(). This is always the same and therefore the searched value expression "#{cc.attrs.value.monthAsString}" results in same Object (and then the same value) of the request.</li>
  </ul>
  
  <p>ComponentStateHelper:</p>
  
  <pre><code>public Object eval(Serializable key, Object defaultValue) {
         Object retVal = get(key);
          if (retVal == null) {
              ValueExpression ve = component.getValueExpression(key.toString());
              if (ve != null) {
                  retVal = ve.getValue(component.getFacesContext().getELContext());
              }
          }
          return ((retVal != null) ? retVal : defaultValue);
      }
  </code></pre>
  
  <p>Why does the component.getFacesContext().getELContext() not hold and ValueExpression.getValue(..) distinguish both "composit component"-component values?</p>
  
  <p>How to get the value of one "composit component"-component value (Ex. selected_month) into a "composit component"-component validator for cross field validation of two "composit component"-components?</p>
  
  <p>Or, what is my mistake?</p>
  
  <p>Wilfdfly 10.1.0
  PrimeFaces 6.1</p>