0

Is that possible to execute some java code before jsf parsing?

My use case: let's say, I have several outputText that are defined in external property file:

<h:outputText value="#{msg['my.example.label']}"/>

And after each of this outputText I want to have another outputText with value of msg key (for debugging purposes).

<h:outputText value="#{msg['my.example.label']}"/>
<h:outputText value="my.example.label"/>

And I don't want to add it manual to each label, but write some code, that can detect #{msg[...]} fragments, extract key and add it after original tag.

Is it possible with JSF?

Kukeltje
  • 12,223
  • 4
  • 24
  • 47
Feedforward
  • 4,521
  • 4
  • 22
  • 34
  • You could do two things. Create a custom component that takes the 'key' as an attribute and inside it both displays the key and the resolved `msg` if in debug mode or just the label when not in debug/developer mode. But you could also create a resource resolver (the 'alternative' part in the answer in https://stackoverflow.com/questions/13655540/read-resource-bundle-properties-in-a-managed-bean and have it return the key and resolved value when in developer mode. – Kukeltje Sep 06 '17 at 21:10

1 Answers1

0

You can create a custom component that extends HtmlOutputText (<h:outputText>). Here an example that i have used for something similar, but showing all expressions (beans, resurces and implicit objects), not only resource variable:

The custom component:

@FacesComponent("com.mycompany.component.CustomOutputText")
public class CustomOutputText extends HtmlOutputText {

    public static final String ATTRIBUTE_VALUE = "value";

    @Override
    public String getFamily() {
        return "com.mycompany.component.customFamily";
    }

    public String getValue() {
        return (String) getStateHelper().eval(ATTRIBUTE_VALUE);
    }

    public String getNotEvalValue() {
        return (String) getValueExpression(ATTRIBUTE_VALUE).getExpressionString();
    }

    public void setValue(String value) {
        getStateHelper().put(ATTRIBUTE_VALUE, value);
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        ResponseWriter writer = context.getResponseWriter();

        writer.startElement("span", this);
        writer.append(getValue());
        writer.endElement("span");

        writer.startElement("p", this);
        writer.append("[expression: " + getNotEvalValue() + "]");
        writer.endElement("p");
    }
}

The taglib:

<namespace>http://com.mycompany/custom-components</namespace>
<tag>
    <tag-name>customOutputText</tag-name>
    <component>
        <component-type>com.mycompany.component.CustomOutputText</component-type>
        <renderer-type>com.mycompany.component.CustomOutputText</renderer-type>
    </component>
    <attribute>
        <name>value</name>
        <required>true</required>
        <type>java.lang.String</type>
    </attribute>
</tag>

Register in web.xml:

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/custom.taglib.xml</param-value>
</context-param>

And, to test, a simple managed bean (in this case, CDI)

@Named
@ViewScoped
public class MyBean implements Serializable {

    private static final long serialVersionUID = 1L;

    public String getSample() {
        return "sample text from bean";
    }   
}

In the xhtml include the taglib, and use the component:

<custom:customOutputText value="#{myBean.sample}" />

And the output is:

sample text from bean

[expression: #{myBean.sample}]

Note that the component will generate 2 html tags, 1 <span> and 1 <p>, consider this for app css styles.

C.P.O
  • 1,213
  • 2
  • 11
  • 29
  • Nice solution. Sort of what I wrote in my comment... But... OP wants to display the 'key' from the expression, not the full expression. You could implement parsing the expression (removing the `#{msg['` part and the `']}` part but then it only works for the msg variant and not e.g. if also a 'field' (e.g. `#{field['my.other.key']}` is used. And it only works for this specific tag (OP should better have used an `outputLabel`, but that is another issue.) But thanks for the answer – Kukeltje Sep 06 '17 at 23:12
  • Thanks, there are many ways to do that, the example is only one of many. Glad to help! – C.P.O Sep 07 '17 at 16:19