Open simasch opened 4 months ago
I wonder if nobody has tried this yet and the Quarkus MyFaces extension is not scanning for @View
. I will investigate.
Standalone Jetty runnner of the example above just so i could make sure it works outside of Quarkus. quarkus-444.zip
mvn clean jetty:run
and navigate to http://localhost:8080/facelet.xhtml
I opened a MyFaces Quarkus Extension ticket: https://issues.apache.org/jira/browse/MYFACES-4668
Also opened this: https://issues.apache.org/jira/browse/MYFACES-4669
I have a fix for Quarkus but waiting to hear back on the escaping issue with the UIOutput
ok for MyFaces I had to update your example to be this using DocType
and removing the <html>
tag.
package org.primefaces.test;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.faces.annotation.View;
import jakarta.faces.application.StateManager;
import jakarta.faces.component.UIComponent;
import jakarta.faces.component.html.HtmlBody;
import jakarta.faces.component.html.HtmlCommandButton;
import jakarta.faces.component.html.HtmlDoctype;
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 htmlDoctype = new HtmlDoctype();
htmlDoctype.setRootElement("html");
rootChildren.add(htmlDoctype);
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);
body.getChildren().add(message);
}
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);
}
}
}
}
I also asked on Mojarra which is the correct behavior https://github.com/eclipse-ee4j/mojarra/issues/5452
Got to the bottom of it. Mojarra is wrong and Myfaces is correct: https://github.com/jakartaee/faces/issues/1796
To do it correctly escape
must be set on the UI output like this.
package org.primefaces.test;
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.HtmlDoctype;
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 htmlDoctype = new HtmlDoctype();
htmlDoctype.setRootElement("html");
rootChildren.add(htmlDoctype);
UIOutput output = new UIOutput();
output.setValue("<html xmlns=\"http://www.w3.org/1999/xhtml\">");
output.getAttributes().put("escape", false);
rootChildren.add(output);
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);
body.getChildren().add(message);
output = new UIOutput();
output.setValue("</html>");
output.getAttributes().put("escape", false);
rootChildren.add(output);
}
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);
}
}
}
}
I tried to add a programmatic view with the
@View
annotation, but when I access http://localhost:8080/facelet.xhml it returns 404