solidgoldpig
solidgoldpig

Reputation: 117

Accessing attributes passed to extended PrimeFaces component

I'm trying to create a custom component to extend PrimeFaces.

I have a simple component called textInput under the test namespace that simply calls the PrimeFaces textInput component and prints out the value passed to an attribute named fieldClass and the names of any attributes passed

if I pass fieldClass as a string:

<test:textInput id="foo" fieldClass="field-foo" />

this is the result

fieldClass = field-foo

[com.sun.faces.facelets.MARK_ID, fieldClass]

If I pass fieldClass as an expression

<ui:param name="bar" value="field-foo"/>
<test:textInput id="foo" fieldClass="#{bar}" />

fieldClass vanishes

fieldClass = NONE

[com.sun.faces.facelets.MARK_ID]

How do I actually get hold of the attributes passed to the component?

Classes used by the custom component follows:

test.components.ExtendInputTextRenderer

package test.components;

import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import org.primefaces.component.inputtext.*;

@FacesRenderer( 
     componentFamily=ExtendInputText.COMPONENT_FAMILY, 
     rendererType=ExtendInputTextRenderer.RENDERER_TYPE 
) 

public class ExtendInputTextRenderer extends InputTextRenderer {
     public static final String RENDERER_TYPE = "com.example.ExtendInputTextRenderer";

     @Override
     public void encodeEnd(FacesContext context, UIComponent component)
                throws java.io.IOException {
          ResponseWriter writer = context.getResponseWriter();
          Map attrs = component.getAttributes();
          String fieldClass = attrs.containsKey("fieldClass") ? (String) attrs.get("fieldClass").toString() : "NONE";
          writer.write("fieldClass = " + fieldClass + "<br/>");
          writer.write(attrs.keySet().toString() + "<br/>");
          super.encodeEnd(context, component);
     }
}

test.components.ExtendInputText

package test.components;

import javax.faces.component.FacesComponent;
import org.primefaces.component.inputtext.InputText;



@FacesComponent(ExtendInputText.COMPONENT_TYPE) 
public class ExtendInputText extends InputText { 
 
     public static final String COMPONENT_FAMILY = "com.example"; 
     public static final String COMPONENT_TYPE = "com.example.ExtendInputText"; 
 
     @Override 
     public String getFamily() { 
          return COMPONENT_FAMILY; 
     } 
 
     @Override 
     public String getRendererType() { 
          return ExtendInputTextRenderer.RENDERER_TYPE; 
     } 
}

Upvotes: 3

Views: 4349

Answers (1)

BalusC
BalusC

Reputation: 1109635

String fieldClass = attrs.containsKey("fieldClass") ? (String) attrs.get("fieldClass").toString() : "NONE";

Your mistake is that you're using containsKey() to check if the property has been specified.

Here's an extract from UIComponent#getAttributes() javadoc:

getAttributes

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

Return a mutable Map representing the attributes (and properties, see below) associated wth this UIComponent, keyed by attribute name (which must be a String). The returned implementation must support all of the standard and optional Map methods, plus support the following additional requirements:

  • The Map implementation must implement the java.io.Serializable interface.
  • Any attempt to add a null key or value must throw a NullPointerException.
  • Any attempt to add a key that is not a String must throw a ClassCastException.
  • 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() - Return false.
    • get() - If the property is readable, call the getter method and return the returned value (wrapping primitive values in their corresponding wrapper classes); otherwise throw IllegalArgumentException.
    • 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 to null, throw IllegalArgumentException.
    • remove() - Throw IllegalArgumentException.

Note that it thus always returns false for containsKey for component's properties. That's because dynamic properties are not stored in the attribute map, but instead in the component instance itself. They're only resolved when calling get().

You need to change the wrong line as follows:

String fieldClass = (String) attrs.get("fieldClass");
if (fieldClass == null) fieldClass = "NONE";

Upvotes: 3

Related Questions