I cannot retrieve attributes that contain EL inside my ViewHandler.
As a minimal example, here's my ViewHandler. It just looks for an attribute "attributeName" and prints out its value.
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;
}
}
This is registered in the faces-config.xml. The xhtml that I'm hitting:
<!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>
The logged output shows that only the non-EL attribute was picked up.
INFO [stdout] (http-/127.0.0.1:8080-1) Found it: 2 + 5
The mistake is here:
if (target.getAttributes().containsKey("attributeName"))
You're using containsKey() to check if the property has been specified. This however won't work if the attribute is a ValueExpression. Here's an extract from UIComponent#getAttributes() javadoc with emphasis:
getAttributes
public abstract java.util.Map<java.lang.String,java.lang.Object> getAttributes()Return a mutable
Maprepresenting the attributes (and properties, see below) associated wth thisUIComponent, keyed by attribute name (which must be aString). The returned implementation must support all of the standard and optionalMapmethods, plus support the following additional requirements:
- The
Mapimplementation must implement thejava.io.Serializableinterface.- Any attempt to add a
nullkey or value must throw aNullPointerException.- Any attempt to add a key that is not a
Stringmust throw aClassCastException.- If the attribute name specified as a key matches a property of this
UIComponent's implementation class, the following methods will have special behavior:
containsKey()- Returnfalse.get()- If the property is readable, call the getter method and return the returned value (wrapping primitive values in their corresponding wrapper classes); otherwise throwIllegalArgumentException.put()- If the property is writeable, call the setter method to set the corresponding value (unwrapping primitive values in their corresponding wrapper classes). If the property is not writeable, or an attempt is made to set a property of primitive type tonull, throwIllegalArgumentException.remove()- ThrowIllegalArgumentException.
Thus, it always returns false for containsKey for component's properties (read: component's ValueExpressions). That's because dynamic properties are not stored in the attribute map, but instead in the component instance itself via UIComponent#setValueExpression() calls. They're only resolved when calling get().
You basically need to change the wrong line as follows, this also works for "static" attributes:
Object value = target.getAttributes().get("attributeName");
if (value != null) {
System.out.println("Found it: " + value);
}
If you would like to check if the attribute is actually being set, even though it would evaluate null like value="#{bean.returnsNull}", then you'd instead like to check if UIComponent#getValueExpression() doesn't return null.
if (target.getValueExpression("attributeName") != null) {
System.out.println("Found it: " + target.getAttributes().get("attributeName"));
}
This does in turn however not work for "static" attributes. You could just combine the checks if necessary, depending on the concrete functional requirements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With