Hello together,

I mentioned that TomEE Plume 10 struggles to resolve the component type
of a composite component, when restoring a view with multiple different
composite components.

I created the following play example:

On the page index.xhtml I am using two different composite components
<cc:output1> and <cc:output2> with componentType
"com.example.components.CompositeOutput1" and
"com.example.components.CompositeOutput2" respectively.

There also is a <h:commandButton> whose action method navigates back to
the current page.

<html xmlns="http://www.w3.org/1999/xhtml"; xmlns:h="jakarta.faces.html" 
xmlns:cc="jakarta.faces.composite/taglib"> <h:body><h:form
id="form"><cc:output1 id="output1"
value="#{valueFace.value}"/><cc:output2 id="output2"
value="#{valueFace.value}"/><h:commandButton value="submit"
action="#{valueFace.increment}"/></h:form></h:body></html>

The composite components consist of a .xhtml file:

<html xmlns="http://www.w3.org/1999/xhtml"; xmlns:h="jakarta.faces.html" 
xmlns:composite="jakarta.faces.composite"> <composite:interface
componentType="com.example.components.CompositeOutput1"><composite:attribute
name="value"
required="true"/></composite:interface><composite:implementation><div id="#{cc.clientId}"> 
<h:outputText binding="#{cc.output1}"/></div>
</composite:implementation></html>

and a java class:

@FacesComponent("com.example.components.CompositeOutput1")
public class CompositeOutput1extends UIInputimplements NamingContainer {

    private UIOutputoutput1;

    @Override public StringgetFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override public void encodeBegin(FacesContext context)throws IOException {
        Object value = getValue();

        this.output1.setValue(value);
    }

    public UIOutputgetOutput1() {
        return output1;
    }

    public void setOutput1(UIOutput output1) {
        this.output1 = output1;
    }
}

You can find the other required files attached.

*Steps to reproduce:*

1. go to the page index.xhtml

2. click the submit button


*Expected behavior:*

When clicking the submit button, one should stay at the same page. The
output values are incremented


*Observed behavior:*

When clicking the submit button, the following exception is thrown:

jakarta.el.PropertyNotFoundException: Die Eigenschaft [output2] wurde für den 
Typ [com.example.components.CompositeOutput1] nicht gefunden
        jakarta.el.BeanELResolver$BeanProperties.get(BeanELResolver.java:261)
        jakarta.el.BeanELResolver.property(BeanELResolver.java:330)
        jakarta.el.BeanELResolver.getType(BeanELResolver.java:82)
        
com.sun.faces.el.DemuxCompositeELResolver._getType(DemuxCompositeELResolver.java:169)
        
com.sun.faces.el.DemuxCompositeELResolver.getType(DemuxCompositeELResolver.java:194)
        org.apache.el.parser.AstValue.setValue(AstValue.java:191)
        org.apache.el.ValueExpressionImpl.setValue(ValueExpressionImpl.java:199)
        
org.apache.webbeans.el22.WrappedValueExpression.setValue(WrappedValueExpression.java:92)
        
com.sun.faces.facelets.el.ContextualCompositeValueExpression.setValue(ContextualCompositeValueExpression.java:126)
        
com.sun.faces.facelets.el.TagValueExpression.setValue(TagValueExpression.java:95)
        jakarta.faces.component.UIComponent.processEvent(UIComponent.java:1875)
        
com.sun.faces.lifecycle.RestoreViewPhase.lambda$deliverPostRestoreStateEvent$0(RestoreViewPhase.java:381)
        
com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:125)
        jakarta.faces.component.UIComponent.visitTree(UIComponent.java:1266)
        jakarta.faces.component.UIComponent.visitTree(UIComponent.java:1278)
        jakarta.faces.component.UIComponent.visitTree(UIComponent.java:1278)
        jakarta.faces.component.UIComponent.visitTree(UIComponent.java:1278)
        jakarta.faces.component.UIForm.visitTree(UIForm.java:344)
        jakarta.faces.component.UIComponent.visitTree(UIComponent.java:1278)
        jakarta.faces.component.UIComponent.visitTree(UIComponent.java:1278)
        
com.sun.faces.lifecycle.RestoreViewPhase.deliverPostRestoreStateEvent(RestoreViewPhase.java:379)
        
com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:223)
        com.sun.faces.lifecycle.Phase.doPhase(Phase.java:72)
        
com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:96)
        com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:131)
        jakarta.faces.webapp.FacesServlet.executeLifecyle(FacesServlet.java:691)
        jakarta.faces.webapp.FacesServlet.service(FacesServlet.java:449)
        org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
        org.apache.openejb.server.httpd.EEFilter.doFilter(EEFilter.java:67)

The same error can be observed, if a composite component is used inside
of another composite component.

This behavior only occurs on TomEE Plume 10.0.0. It doesn't on TomEE
Plus 10.0.0 and Wildfly 35.

Is this a known issue? Is there a workaround? Defining the components in
a taglib file did not solve the problem.

Thank you for your help

Kind regards

Till Gräfenberg

Attachment: index.xhtml
Description: application/xhtml

Attachment: output1.xhtml
Description: application/xhtml

Attachment: output2.xhtml
Description: application/xhtml

package com.example.faces;

import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Named;

import java.io.Serializable;

@Named("valueFace")
@SessionScoped
public class ValueFace implements Serializable {

    Integer value = 42;

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    public void increment() {
        this.value = this.value + 1;
    }

}
package com.example.components;

import jakarta.faces.component.*;
import jakarta.faces.context.FacesContext;

import java.io.IOException;

@FacesComponent("com.example.components.CompositeOutput1")
public class CompositeOutput1 extends UIOutput implements NamingContainer {

    private UIOutput output1;

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        Object value = getValue();

        this.output1.setValue(value);
    }

    public UIOutput getOutput1() {
        return output1;
    }

    public void setOutput1(UIOutput output1) {
        this.output1 = output1;
    }
}
package com.example.components;

import jakarta.faces.component.*;
import jakarta.faces.context.FacesContext;

import java.io.IOException;

@FacesComponent("com.example.components.CompositeOutput2")
public class CompositeOutput2 extends UIOutput implements NamingContainer {

    private UIOutput output2;

    @Override
    public String getFamily() {
        return UINamingContainer.COMPONENT_FAMILY;
    }

    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        Object value = getValue();

        this.output2.setValue(value);
    }

    public UIOutput getOutput2() {
        return output2;
    }

    public void setOutput2(UIOutput output) {
        this.output2 = output;
    }
}

Reply via email to