Accessing JSF2 composite component attributes in backing component
Asked Answered
H

1

6

I'm developing a JSF2/Primefaces app and I'm having trouble with accessing attributes defined in an interface of a composite component in this component's backing bean.

My component is defined as follows:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:composite="http://java.sun.com/jsf/composite">

<composite:interface componentType="testComponent">
    <composite:attribute name="text" required="true" type="java.lang.String" />
</composite:interface>

<composite:implementation>

    <h:outputText value="Passed text is: #{cc.attrs.text}" />

</composite:implementation>

</html>

It is stored in a file called text.xhtml located in: application/src/main/webapp/resources/my_component directory.

I use this component on another page (which is a Facelets composition element) like so:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:myc="http://java.sun.com/jsf/composite/my_component"
    template="./resources/templates/template.xhtml">

<ui:define name="content"> 
    <h:form id="products">
        <myc:test id="test" text="A text" />
    </h:form>
</ui:define>    

</ui:composition>

The backing component class is defined as follows:

package my.application.component;

import javax.faces.component.FacesComponent;
import javax.faces.component.UINamingContainer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@FacesComponent ( value="testComponent" )
public class TestComponent extends UINamingContainer {
    Logger log = LoggerFactory.getLogger(TestComponent.class);

    public TestComponent() {
        log.debug("TestComponent constructor");
        log.debug("getAttributes().size(): " + getAttributes().size());
    }
}

The component itself works as expected. The using page renders Passed text is: A text output. Also, logger output displays log messages from TestComponent constructor, so it seems that the component xml definition is correctly bound with the TestComponent class.

Now, the problem is that the getAttributes() method invoked in TestComponent constructor always returns a zero-sized map. If I understand this correctly, I should be able to access the text attribute declared in component's interface using a call:

getAttributes().get("text");

in the TestComponent class, but it always returns null as the attributes map is empty.

I also tried to access the text attribute using a call:

String text = FacesContext.getCurrentInstance().getApplication(). evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{cc.attrs.text}", String.class));

but it also resolves to null.

What am I doing wrong? Any tips will be much appreciated as I have no idea what to try next.

/Tukasz.

Humility answered 20/2, 2012 at 8:55 Comment(0)
S
5

My guess is that the constructor is too early to reference those attributes.

JSF will construct an instance of the backing component first, and will then at some point give it a reference to its attributes. In a method that's called later, eg the encode method, you should have access to them.

Stipe answered 20/2, 2012 at 9:26 Comment(3)
Hi Mike. Thanks. I'll give it a try and check if the attributes are accessible in encode method.Riding
Hi again. Yes. The attributes are accessible in the encode[All|Begin|End|Childen](FacesContext context) methods. Thank you very much for the help. But I still wonder if one of these methods is the right place to access the attributes if I want to use them in some way before my component is rendered. In a @ManagedBeans I use @PostConstruct methods for such purpose, but this doesn't seem to work in a @FacesComponent class.Riding
Maybe someone should file a request for that? @PostConstruct in @FacesComponent would be great!Choirmaster

© 2022 - 2024 — McMap. All rights reserved.