Kompozyt złożony z niestandardowym komponentem podkładu dziwnie pęka po zagnieżdżeniu wewnątrz interfejsu użytkownika: powtórz

Mój problem w skrócie jest taki, że mam komponent złożony z określonym typem komponentu. Kiedy używam samego komponentu kompozytowego na stronie, działa dobrze. Gdy zagnieżdżam go w innym komponencie złożonym (także wewnątrz ui: repeat), otrzymuję wyjątek próbujący znaleźć właściwości, które zdefiniowałem w klasie componentType wewnątrz kontenera UINamingContainer - co jest niewłaściwą klasą. Odkryłem, że mogę rozwiązać ten problem, zastępując gocc.whatever zcomponent.parent.parent.parent.whatever ale uważam, że to trochę hack. Zakładam, że robię coś głupiego, co dezorientuje JSF, ale nie jestem pewien, co to jest lub co powinienem robić inaczej.

Teraz, w niesamowitych szczegółach, mam następujący komponent złożony:

<?xml version='1.0' encoding='UTF-8' ?>
<ui:component xmlns:ui="http://java.sun.com/jsf/facelets"
              xmlns:cc="http://java.sun.com/jsf/composite"
              xmlns:ice="http://www.icesoft.com/icefaces/component"
              xmlns:f="http://java.sun.com/jsf/core">
  <cc:interface componentType="edu.nrao.sss.tools.resrccat.ui.support.LinearVelocityUIComponent">
    <cc:attribute name             = "value"
                  class            = "edu.nrao.sss.measure.LinearVelocity"
                  required         = "true"
                  shortDescription = "The LinearVelocity value to show or edit."/>

    <cc:attribute name             = "separate-units"
                  type             = "boolean"
                  default          = "true"
                  shortDescription = "If true, provide a drop-box to edit the units separately from the value."/>
  </cc:interface>
  <cc:implementation>
    <ice:inputText id="velocity" value="#{cc.attrs.value}" rendered="#{not cc.attrs['separate-units']}"/>

    <ui:fragment rendered="#{cc.attrs['separate-units']}">
      <ice:inputText id="velocityDecimal" value="#{cc.velocityDecimal}"/>
      <ice:selectOneMenu id="velocityUnits" value="#{cc.velocityUnits}">
        <f:selectItems value="#{siFactory.linearVelocityUnits}"/>
      </ice:selectOneMenu>
    </ui:fragment>
  </cc:implementation>
</ui:component>

Składnikiem jest to:

@FacesComponent("edu.nrao.sss.tools.resrccat.ui.support.LinearVelocityUIComponent")
public class LinearVelocityUIComponent extends UIInput implements NamingContainer {

  @Override public String getFamily() {
    return UINamingContainer.COMPONENT_FAMILY;
  }

  public LinearVelocity getVelocity() {
    return (LinearVelocity) getValueExpression("value").getValue(FacesContext.getCurrentInstance().getELContext());
  }

  public void setVelocity(LinearVelocity newVelocity) {
    getValueExpression("value").setValue(FacesContext.getCurrentInstance().getELContext(), newVelocity);
  }

  public BigDecimal getVelocityDecimal() {
    return getVelocity().getValue();
  }

  public LinearVelocityUnits getVelocityUnits() {
    return getVelocity().getUnits();
  }

  public void setVelocityDecimal(BigDecimal newVelocity) {
    setVelocity(new LinearVelocity(newVelocity, getVelocityUnits()));
  }

  public void setVelocityUnits(LinearVelocityUnits units) {
    setVelocity(new LinearVelocity(getVelocityDecimal(), units));
  }
}

Kiedy używam tego komponentu osobno na stronie, wszystko jest w porządku:

<p>Your linear velocity is <rct:linear-velocity value="#{test.velocity}"/></p>

Kiedy zagnieżdżam go w innym komponencie złożonym takim jak ten:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:component xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ice="http://www.icesoft.com/icefaces/component"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:cc="http://java.sun.com/jsf/composite"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:rct="http://java.sun.com/jsf/composite/components/rct">
  <cc:interface>
    <cc:attribute name="specs"        required="true"/>
    <cc:attribute name="type"         default="line"/>
  </cc:interface>
  <cc:implementation>
    <table class="iceDatTbl">
      <thead>
        <tr>
          ...
          <th class="iceDatTblColHdr2">Minimum<br/>Span</th> 
          ...
        </tr>
      </thead>
      <tbody>
        <ui:repeat var="spec" value="#{cc.attrs.specs}" varStatus="stat">
          <tr class="#{stat.even ? 'iceDatTblRow1' : 'iceDatTblRow2'}">
            ...
            <td class="iceDatTblCol2">
              Req: <rct:linear-velocity value="#{spec.minimumSpan}"/><br/>
              Sug: #{spec.suggestedMinimumSpan}
            </td>
            ...
          </tr>
        </ui:repeat>
      </tbody>
    </table>
  </cc:implementation>
</ui:component>

Mam ten wyjątek:

Nov 19, 2012 4:10:37 PM org.icefaces.impl.application.ExtendedExceptionHandler handle
WARNING: queued exception
javax.el.PropertyNotFoundException: /resources/components/rct/linear-velocity.xhtml @20,113 value="#{cc.velocityDecimal}": Property 'velocityDecimal' not found on type javax.faces.component.UINamingContainer
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
    at javax.faces.component.UIOutput.getValue(UIOutput.java:169)
    at com.sun.faces.facelets.component.UIRepeat$SavedState.populate(UIRepeat.java:823)
    at com.sun.faces.facelets.component.UIRepeat.saveChildState(UIRepeat.java:369)
    at com.sun.faces.facelets.component.UIRepeat.saveChildState(UIRepeat.java:375)
    at com.sun.faces.facelets.component.UIRepeat.saveChildState(UIRepeat.java:375)
    at com.sun.faces.facelets.component.UIRepeat.saveChildState(UIRepeat.java:355)
    at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:440)
    at com.sun.faces.facelets.component.UIRepeat.visitTree(UIRepeat.java:613)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at javax.faces.component.UINamingContainer.visitTree(UINamingContainer.java:163)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at org.icefaces.impl.component.UISeriesBase.visitRows(UISeriesBase.java:1174)
    at org.icefaces.impl.component.UISeriesBase.visitTree(UISeriesBase.java:1065)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at javax.faces.component.UIForm.visitTree(UIForm.java:344)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at javax.faces.component.UIComponent.visitTree(UIComponent.java:1601)
    at org.icefaces.impl.event.RestoreResourceDependencies.processEvent(RestoreResourceDependencies.java:24)
    at javax.faces.event.SystemEvent.processListener(SystemEvent.java:106)
    at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:2168)
    at com.sun.faces.application.ApplicationImpl.invokeListenersFor(ApplicationImpl.java:2144)
    at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:302)
    at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:246)
    at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:812)
    at javax.faces.component.UIViewRoot.encodeBegin(UIViewRoot.java:962)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1755)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:402)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    at com.ocpsoft.pretty.faces.application.PrettyViewHandler.renderView(PrettyViewHandler.java:163)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at com.ocpsoft.pretty.PrettyFilter.doFilter(PrettyFilter.java:145)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:749)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:487)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:412)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339)
    at com.ocpsoft.pretty.PrettyFilter.doFilter(PrettyFilter.java:137)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at edu.nrao.sss.webapp.LookupUserFilter.doFilter(LookupUserFilter.java:57)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.jasig.cas.client.util.HttpServletRequestWrapperFilter.doFilter(HttpServletRequestWrapperFilter.java:50)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.jasig.cas.client.validation.AbstractTicketValidationFilter.doFilter(AbstractTicketValidationFilter.java:167)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.jasig.cas.client.authentication.AuthenticationFilter.doFilter(AuthenticationFilter.java:111)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

Zastępcą, którą mogę zrobić, aby to działało, jest:

<ui:fragment rendered="#{cc.attrs['separate-units']}">
  <ice:inputText id="velocityDecimal" value="#{component.parent.parent.parent.velocityDecimal}"/>
  <ice:selectOneMenu id="velocityUnits" value="#{component.parent.parent.parent.velocityUnits}">
    <f:selectItems value="#{siFactory.linearVelocityUnits}"/>
  </ice:selectOneMenu>
</ui:fragment>

To jest naprawdę złe i historycznie za każdym razem, gdy próbuję sprawić, by JSF pracował w ten sposób, kilka miesięcy później niszczy moje życie. Byłbym bardzo wdzięczny za każdą pomoc! Uwielbiam JSF i naprawdę cieszę się z używania komponentów kompozytowych do strukturyzowania rzeczy, ale naprawdę muszę umieć zagnieżdżać komponenty kompozytowe.

Edytować: Odkryłem, że w Glassfish komponent nie jest renderowany w ogóle. Powoduje ten sam błąd (UINamingContainer nie ma tej właściwości LinearVelocityUIComponent ma) zagnieżdżony w innym komponencie.

questionAnswers(1)

yourAnswerToTheQuestion