<f:attribute value =“#{some EL expression}}”>通过getAttributes()。containsKey()找不到

Eva*_*les 3 jsf attributes el jsf-2

我无法检索到包含EL的属性ViewHandler

作为最小的示例,这是我的ViewHandler。它只是寻找一个属性"attributeName"并打印出它的值。

public class MiniViewHandler extends ViewHandlerWrapper
{
  private ViewHandler defaultViewHandler = null;

  public MiniViewHandler()
  {
  }

  public MiniViewHandler(ViewHandler defaultViewHandler)
  {
    super();
    this.defaultViewHandler = defaultViewHandler;
  }

  @Override
  public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException, FacesException
  {
    viewToRender.visitTree(VisitContext.createVisitContext(context),
            new VisitCallback()
            {

              @Override
              public VisitResult visit(VisitContext context, UIComponent target)
              {
                if (target.getAttributes().containsKey("attributeName"))
                {
                  System.out.println("Found it: " + target.getAttributes().get("attributeName"));
                }

                return VisitResult.ACCEPT;
              }
            }
    );

    defaultViewHandler.renderView(context, viewToRender);
  }

  @Override
  public ViewHandler getWrapped()
  {
    return defaultViewHandler;
  }
}
Run Code Online (Sandbox Code Playgroud)

这是在中注册的faces-config.xml。我正在击中的xhtml:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
<h:body>
    <f:view>
        <f:attribute name="attributeName" value="#{2 + 5}"/>
    </f:view>
    <f:view>
        <f:attribute name="attributeName" value="2 + 5"/>
    </f:view>
</h:body>
</html>
Run Code Online (Sandbox Code Playgroud)

记录的输出显示仅拾取了非EL属性。

INFO  [stdout] (http-/127.0.0.1:8080-1) Found it: 2 + 5
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 5

错误在这里:

if (target.getAttributes().containsKey("attributeName"))
Run Code Online (Sandbox Code Playgroud)

您正在containsKey()检查是否已指定属性。但是,如果属性为,则此方法将无效ValueExpression。以下是UIComponent#getAttributes()javadoc的摘录,重点是:

getAttributes

public abstract java.util.Map<java.lang.String,java.lang.Object> getAttributes()

返回一个可变的变量,Map该变量表示与此this关联的属性(和属性,请参见下文)UIComponent,并以属性名称(必须为String)作为关键字。返回的实现必须支持所有标准和可选Map方法,并支持以下附加要求:

  • Map实现必须实现该java.io.Serializable接口。
  • 任何添加null键或值的尝试都必须抛出NullPointerException
  • 任何添加非String必需键的尝试都必须抛出ClassCastException
  • 如果指定为键的属性名称与此UIComponent实现类的属性匹配,则以下方法将具有特殊行为:
    • containsKey()-返回false
    • get()-如果该属性可读,则调用getter方法并返回返回的值(将原始值包装在其相应的包装器类中);否则抛出IllegalArgumentException
    • put()-如果该属性是可写的,则调用setter方法以设置相应的值(将原始值包装在其相应的包装器类中)。如果该属性不可写,或者尝试将原始类型的属性设置为nullthrow IllegalArgumentException
    • remove()-扔IllegalArgumentException

因此,它总是返回falsecontainsKey对组件的属性(读:组件的ValueExpression多个)。这是因为动态属性未存储在属性映射中,而是通过UIComponent#setValueExpression()调用存储在组件实例本身中。他们只会在打电话时解决get()

您基本上需要按以下方式更改错误的行,这也适用于“静态”属性:

Object value = target.getAttributes().get("attributeName");
if (value != null) {
    System.out.println("Found it: " + value);
}
Run Code Online (Sandbox Code Playgroud)

如果您想检查该属性是否真的被设置,即使它的评估结果为nulllike value="#{bean.returnsNull}",那么您还是想检查该属性是否UIComponent#getValueExpression()未返回null

if (target.getValueExpression("attributeName") != null) {
    System.out.println("Found it: " + target.getAttributes().get("attributeName"));
}
Run Code Online (Sandbox Code Playgroud)

反过来,这对于“静态”属性也不起作用。根据具体的功能要求,您可以仅在必要时组合检查。