Skip to content

Programmatic View with UIOutput #5452

@melloware

Description

@melloware

Sorry to post this here but I can't seem to find in the spec what is the correct behavior between MyFaces and Mojarra.

Original report: melloware/quarkus-faces#444

When creating a programmatic view with the following code:

package org.apache.myfaces.core.extensions.quarkus.showcase.view;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.annotation.View;
import jakarta.faces.application.StateManager;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.UIOutput;
import jakarta.faces.component.html.HtmlBody;
import jakarta.faces.component.html.HtmlCommandButton;
import jakarta.faces.component.html.HtmlForm;
import jakarta.faces.component.html.HtmlOutputText;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.facelets.Facelet;

@View("/facelet.xhtml")
@ApplicationScoped
public class FaceletView extends Facelet
{

    @Override
    public void apply(FacesContext facesContext, UIComponent parent)
    {
        if (!facesContext.getAttributes().containsKey(StateManager.IS_BUILDING_INITIAL_STATE))
        {
            return;
        }

        var components = new ComponentBuilder(facesContext);
        var rootChildren = parent.getChildren();

        var doctype = new UIOutput();
        doctype.setValue("<!DOCTYPE html>");
        rootChildren.add(doctype);

        var htmlTag = new UIOutput();
        htmlTag.setValue("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
        rootChildren.add(htmlTag);

        HtmlBody body = components.create(HtmlBody.COMPONENT_TYPE);
        rootChildren.add(body);

        HtmlForm form = components.create(HtmlForm.COMPONENT_TYPE);
        form.setId("form");
        body.getChildren().add(form);

        HtmlOutputText message = components.create(HtmlOutputText.COMPONENT_TYPE);
        message.setId("message");

        HtmlCommandButton actionButton = components.create(HtmlCommandButton.COMPONENT_TYPE);
        actionButton.setId("button");
        actionButton.addActionListener(
                e -> message.setValue("Hello, World! Welcome to Faces 4.0 on Jakarta EE 10"));
        actionButton.setValue("Greet");

        form.getChildren().add(actionButton);

        parent.getChildren().add(message);

        htmlTag = new UIOutput();
        htmlTag.setValue("</html>");
        rootChildren.add(htmlTag);
    }

    private static class ComponentBuilder
    {
        FacesContext facesContext;

        ComponentBuilder(FacesContext facesContext)
        {
            this.facesContext = facesContext;
        }

        @SuppressWarnings("unchecked")
        <T> T create(String componentType)
        {
            try
            {
                return (T) facesContext.getApplication().createComponent(componentType);
            }
            catch (ClassCastException e)
            {
                throw new IllegalArgumentException("Component type " + componentType + " is not valid.", e);
            }
        }
    }
}

Attached is the reproducer:
programmatic_view.zip

Run mvn clean jetty:run -Pmojarra40 and go to http://localhost:8080/facelet.xhml and Mojarra does this

image

Run mvn clean jetty:run -Pmyfaces40 and go to http://localhost:8080/facelet.xhml and MyFaces does this
image

the question comes down to "who is doing the right thing"? MyFaces seems to escape the following code but Mojarra does not

 var htmlTag = new UIOutput();
htmlTag.setValue("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
rootChildren.add(htmlTag);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions