0

简短的摘要:

项目:一个复合组件,可让我过滤列表并更新外部组件

问题:myfaces 2.1.10 有效,mojarra 2.2.1 无效,但我想使用 jsf 2.2

复合组件filteredList.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:composite="http://java.sun.com/jsf/composite" xmlns:ui="http://java.sun.com/jsf/facelets">
  <composite:interface>
    <composite:attribute name="label" required="false" default="filter" type="java.lang.String" />
    <composite:attribute name="filter" required="true" type="java.lang.String" />
    <composite:attribute name="list" required="true" type="java.util.List" />
    <composite:attribute name="valueMask" required="false" type="" />
    <composite:attribute name="outputId" required="false" type="java.lang.String" />
    <composite:attribute name="height" required="false" default="128" type="java.lang.Integer" />
    <composite:attribute name="width" required="false" default="128" type="java.lang.Integer" />
    <composite:attribute name="destinationId" required="false" type="java.lang.String" />
    <composite:attribute name="rowClasses" required="false" type="java.lang.String" />
    <composite:attribute name="hoverClass" required="false" default="" type="java.lang.String" />
    <composite:attribute name="innerCellClasses" required="false" default="" type="java.lang.String" />
    <composite:attribute name="repeatClassOdd" required="false" default="" type="java.lang.String" />
    <composite:attribute name="repeatClassEven" required="false" default="" type="java.lang.String" />
  </composite:interface>
  <composite:implementation>
    <h:outputStylesheet name="css/elements.css" />
    <h:panelGrid columns="2">
      <h:outputText value="#{composite.attrs.label}" />
      <h:inputText id="filterfield" value="#{composite.attrs.filter}">
        <f:ajax event="keyup" render="table" />
      </h:inputText>
    </h:panelGrid>
    <div id="box#{cc.clientId}" style="overflow: auto">
      <h:dataTable id="table" value="#{composite.attrs.list}" var="elem" rowClasses="#{composite.attrs.rowClasses}">
        <h:column>
          <div id="choose#{elem.id}" style="cursor: pointer" class="#{composite.attrs.hoverClass}">
            <h:outputText value="#{elem.html}" rendered="#{elem.renderHtml}" />
            <h:dataTable value="#{elem.list}" var="l" rendered="#{elem.renderDatatable}" rowClasses="#{composite.attrs.innerCellClasses}">
              <h:column>
                <h:outputText value="#{l}" />
              </h:column>
            </h:dataTable>
            <ui:repeat value="#{elem.list}" var="l" varStatus="index" rendered="#{elem.renderRepeat}" columnClasses="#{composite.attrs.innerCellClasses}">
              <div class="#{index.odd ? composite.attrs.repeatClassOdd : composite.attrs.repeatClassEven}" style="display: inline">
                <h:outputText value="#{l}" />
              </div>
            </ui:repeat>
          </div>
          <ui:fragment rendered="#{composite.attrs.destinationId != null}">
            <script type="text/javascript">
              $(document).ready(function(){
                $("[id='choose#{elem.id}']").click(function(){
                  $("[id='#{composite.attrs.destinationId}']").val("#{elem.id}");
                  <ui:fragment rendered="#{cc.attrs.valueMask != null}">
                    $("[id='#{composite.attrs.outputId}']").text("#{composite.attrs.valueMask.getMask(elem.id)}");
                  </ui:fragment>
                  $("[id='#{composite.attrs.destinationId}']").trigger('change');
                });
              });
            </script>
          </ui:fragment>
        </h:column>
      </h:dataTable>
    </div>
    <script type="text/javascript">
      $(document).ready(function(){
        $("[id='box#{composite.clientId}']").height(#{composite.attrs.height}).width(#{composite.attrs.width});
      });
    </script>
  </composite:implementation>
</ui:composition>

该组件的用法:

<mycomponent:filteredList valueMask="#{testAction.valueMask}" label="label.filter" list="#{testAction.listFilter.list}" filter="#{testAction.listFilter.filter}" height="128" width="384" rowClasses="odd,even" hoverClass="hoverClass" inputfieldClasses="stayontop,stayontop" repeatClassOdd="oddy"
        repeatClassEven="eveny" />

使用类TestFilter:

public class TestFilter implements FilterInterface
{
  private String filter;

  @Override
  public List<ListFilterElem> doFilter(List<ListFilterElem> unfilteredList)
  {
    if (filter == null || filter.trim().equals(""))
    {
      return unfilteredList;
    }
    else
    {
      String[] s = filter.split("\\s+");
      Set<ListFilterElem> filtered = new LinkedHashSet<ListFilterElem>();
      for (String f : s)
      {
        for (ListFilterElem e : unfilteredList)
        {
          if (e.containsIgnoreCase(f))
          {
            filtered.add(e);
          }
        }
      }
      return new ArrayList<ListFilterElem>(filtered);
    }
  }

  @Override
  public String getFilter()
  {
    return filter;
  }

  @Override
  public void setFilter(String filter)
  {
    this.filter = filter;
  }
}

使用的类TestListFilterElem:

public class TestListFilterElem implements ListFilterElem
{
  private Integer id;
  private List<String> subList;

  public TestListFilterElem(Integer id, List<String> subList)
  {
    this.id = id;
    this.subList = subList;
  }

  @Override
  public String getHtml()
  {
    StringBuilder buf = new StringBuilder();
    for (String s : subList)
    {
      buf.append(s);
      buf.append(" ");
    }
    return buf.toString();
  }

  @Override
  public Integer getId()
  {
    return id;
  }

  @Override
  public Boolean containsIgnoreCase(String needle)
  {
    return getHtml().toLowerCase().contains(needle.toLowerCase());
  }

  @Override
  public List<String> getList()
  {
    return subList;
  }

  @Override
  public Boolean getRenderDatatable()
  {
    return false;
  }

  @Override
  public Boolean getRenderHtml()
  {
    return false;
  }

  @Override
  public Boolean getRenderRepeat()
  {
    return true;
  }
}

使用的类 ListFilter:

public class ListFilter
{
  private List<ListFilterElem> list;
  private FilterInterface filterInterface;

  public ListFilter(FilterInterface filterInterface)
  {
    this.filterInterface = filterInterface;
    list = new ArrayList<ListFilterElem>();
  }

  public void addListElem(ListFilterElem elem)
  {
    list.add(elem);
  }

  public void addListElems(List<ListFilterElem> elems)
  {
    list.addAll(elems);
  }

  public List<ListFilterElem> getList()
  {
    return filterInterface.doFilter(list);
  }

  public void setFilter(String filter)
  {
    filterInterface.setFilter(filter);
  }

  public String getFilter()
  {
    return filterInterface.getFilter();
  }
}

使用的类掩码:

public class Mask implements MaskInterface
{
  private Integer ensureInteger(Object o) throws Exception
  {
    if (o == null)
    {
      return null;
    }
    else if (o instanceof Integer)
    {
      return (Integer) o;
    }
    else if (o instanceof String)
    {
      return new Integer((String) o);
    }
    else
    {
      throw new Exception("cannot convert " + o.getClass() + " to Integer");
    }
  }

  @Override
  public String getMask(Object o)
  {
    try
    {
      switch (ensureInteger(o))
      {
        case 1: return "first line";
        case 2: return "second line";
        case 3: return "third line";
        default: return "unknown";
      }
    }
    catch (Exception e)
    {
      return e.getMessage();
    }
  }
}

使用的类 ValueMask:

public class ValueMask
{
  private MaskInterface maskInterface;

  public ValueMask(MaskInterface maskInterface)
  {
    this.maskInterface = maskInterface;
  }

  public String getMask(Object o)
  {
    return maskInterface.getMask(o);
  }
}

使用的类TestAction:

@ManagedBean
@SessionScoped
public class TestAction
{
  private ListFilter listFilter;
  private String variable;

  public ListFilter getListFilter()
  {
    if (listFilter == null)
    {
      listFilter = new ListFilter(new TestFilter());
      listFilter.addListElem(new TestListFilterElem(1, Arrays.asList(new String[]{"this", "is", "the", "first", "list"})));
      listFilter.addListElem(new TestListFilterElem(2, Arrays.asList(new String[]{"second", "list"})));
      listFilter.addListElem(new TestListFilterElem(3, Arrays.asList(new String[]{"(brackets", "(in", "(brackets)))"})));
    }
    return listFilter;
  }

  public ValueMask getValueMask()
  {
    return new ValueMask(new Mask());
  }
}

mojarra 的 Maven 依赖项:

<dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-api</artifactId>
  <version>2.2.1</version>
</dependency>
<dependency>
  <groupId>com.sun.faces</groupId>
  <artifactId>jsf-impl</artifactId>
  <version>2.2.1</version>
</dependency>

myfaces 的 Maven 依赖项:

<dependency>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-api</artifactId>
  <version>2.1.10</version>
</dependency>
<dependency>
  <groupId>org.apache.myfaces.core</groupId>
  <artifactId>myfaces-impl</artifactId>
  <version>2.1.10</version>
</dependency>

Stacktrace 如果使用 mojarra:

SEVERE: Servlet.service() for servlet [FacesServlet] in context with path [/TestJsfComponents] threw exception [null] with root cause
java.lang.NullPointerException
  at java.util.Hashtable.put(Hashtable.java:542)
  at java.beans.FeatureDescriptor.setValue(FeatureDescriptor.java:194)
  at com.sun.faces.facelets.tag.composite.AttributeHandler$CCAttributePropertyDescriptor.getValue(AttributeHandler.java:210)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler$CompositeComponentMetaRuleset$CompositeMetadataTarget.getPropertyType(CompositeComponentTagHandler.java:464)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler$CompositeComponentRule.applyRule(CompositeComponentTagHandler.java:540)
  at com.sun.faces.facelets.tag.MetaRulesetImpl.finish(MetaRulesetImpl.java:173)
  at javax.faces.view.facelets.MetaTagHandler.setAttributes(MetaTagHandler.java:127)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.setAttributes(DelegatingMetaTagHandler.java:102)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.setAttributes(CompositeComponentTagHandler.java:245)
  at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:181)
  at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
  at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
  at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
  at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.applyNextHandler(DelegatingMetaTagHandler.java:137)
  at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:190)
  at javax.faces.view.facelets.DelegatingMetaTagHandler.apply(DelegatingMetaTagHandler.java:120)
  at javax.faces.view.facelets.CompositeFaceletHandler.apply(CompositeFaceletHandler.java:95)
  at com.sun.faces.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:93)
  at com.sun.faces.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:87)
  at com.sun.faces.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:161)
  at com.sun.faces.application.view.FaceletViewHandlingStrategy.buildView(FaceletViewHandlingStrategy.java:980)
  at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:99)
  at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
  at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
  at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
  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:502)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
  at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
  at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
  at java.lang.Thread.run(Thread.java:722)

问题:

如果我使用 myfaces,组件会被渲染并工作(过滤元素正在通过 ajax 即时减少列表),但如果我使用 mojarra(甚至 mojarra 是 2.2.1,myfaces 只是 2.1.10),组件不是由于上面显示的堆栈跟踪而呈现。

为什么会这样?我该怎么做才能让 mojarra 与这个复合组件一起工作?

注释:

这种用法(过滤器类等)的复杂性是由于稍后在另一个复合组件中使用该组件,因此上面提到的接口和实现是必要的。

4

1 回答 1

0

过了一会儿,我发现了问题:

<composite:attribute name="valueMask" required="false" type="" />

属性类型为空。似乎 myfaces 原谅了这一点,而 mojarra 没有。对于这样的错误,我更喜欢更好的堆栈跟踪(消息)。

尽管如此,删除 type 解决了这个问题(在我的例子中,我给 type 我需要的完全合格的类)。

于 2013-08-05T08:24:03.523 回答