eclipse-ee4j / glassfish

Eclipse GlassFish
https://eclipse-ee4j.github.io/glassfish/
387 stars 145 forks source link

Can not access Record via property in EL #25052

Open hantsy opened 4 months ago

hantsy commented 4 months ago

Environment Details


Problem Description

EL 6.0 supports record, but I have tried in a simple facelets page, failed to access the property.

...faces-examples/customer.xhtml: The class 'com.example.Customer' 
does not have the property 'firstName'.

The example project: https://github.com/hantsy/jakartaee11-sandbox/tree/master/faces

The back bean:

@RequestScoped
@Named
public class CustomerBean {
    private final static Logger LOGGER= Logger.getLogger(CustomerBean.class.getName());

    @Inject
    FacesContext facesContext;

    private Customer customer;

    public Customer getCustomer() {
        return customer;
    }

    //@PostConstruct
    // use faces event to initialize it
    public void init(PreRenderViewEvent event) {
        if(facesContext.isPostback()){
            LOGGER.log(Level.INFO, "postback, skipping initialization");
            return;
        }

        LOGGER.log(Level.INFO, "initializing");
        customer = new Customer(
                "Foo",
                "Bar",
                new EmailAddress[]{
                        new EmailAddress("foo@example.com", true),
                        new EmailAddress("bar@example.com", false)
                },
                new Address("123 Main St", "Anytown", "CA", "12345")
        );
        LOGGER.log(Level.INFO, "initialized");
    }
}

public record Customer(
        String firstName,
        String lastName,
        EmailAddress[] emailAddresses,
        Address address
) {
}
record EmailAddress(
        String email,
        Boolean primary
) {
}
record Address(
        String street,
        String city,
        String state,
        String zipCode
) {
}

The facelets template:

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="jakarta.faces.facelets"
      xmlns:f="jakarta.faces.core"
      xmlns:h="jakarta.faces.html">
<f:view>
    <f:metadata>
        <f:event listener="#{customerBean.init}" type="preRenderView"/>
    </f:metadata>
    <h:head>
        <title>Express Language 6.0!</title>
    </h:head>
    <h:body>
        <h1>Express Language 6.0</h1>

        <div>
            <strong>#{customerBean.customer.firstName +' ' +customerBean.customer.lastName}</strong>
            <hr/>
        </div>
        <div>Emails: (#{customerBean.customer.emailAddresses.length})</div>
        <ul>
            <ui:repeat value="#{customerBean.customer.emailAddresses}" var="email">
                <li>#{email.email}(#{email.primary?'O':'X'})</li>
            </ui:repeat>
        </ul>
        <div>
            #{customerBean.customer.address.street},
            #{customerBean.customer.address.city},
            #{customerBean.customer.address.state},
            #{customerBean.customer.address.zipCode},
        </div>
    </h:body>
</f:view>
</html>
arjantijms commented 4 months ago

As a quick test, within GF (in a servlet, bean, whatever) you could try invoking Expression Language "manually" (using the universal Java SE way) to see if records work. Normally the RecordELResolver should be added just before the BeanELResolver.

Start with

ELProcessor elProcessor = new ELProcessor();

And then work with that on your types (just as a smoke test)

Tbh, I did not take a look whether extra setup is required in Mojarra. There probably is.

hantsy commented 4 months ago

@arjantijms Tried it in a separate project, worked well.

https://github.com/hantsy/jakartaee11-sandbox/blob/master/el/src/main/java/com/example/ELExample.java

arjantijms commented 4 months ago

Thank you very much, so the API and optionally perhaps Expressly works correct here.

I'll have to figure out where to add it in mojarra

hantsy commented 3 months ago

@arjantijms Still failed in Glassfish 8.0.0-M7

arjantijms commented 3 months ago

@hantsy the following line in your example will crash any way:

<strong>#{customerBean.customer.firstName +' ' +customerBean.customer.lastName}</strong>

Removing that and with the latest 4.1.2-SNAPSHOT it does seem to work.

faces_el6

https://github.com/eclipse-ee4j/mojarra/pull/5481

OndroMih commented 3 months ago

In <strong>#{customerBean.customer.firstName +' ' +customerBean.customer.lastName}</strong>, plain + should be replaced with +=, which is an operator for string concatenation. Then it should work. Plain + only works with numbers.

hantsy commented 3 months ago

Sorry, I forgot to update this. But here it indicated some info similar to can not access property customer.firstName, so I thought the EL resolver for record was still not applied.

arjantijms commented 3 months ago

@hantsy If you want to try again, this binary https://ci.eclipse.org/glassfish/job/glassfish_build-and-test-using-jenkinsfile/job/PR-25108/1/artifact/bundles/glassfish.zip includes the updated Mojarra 4.1.2.

hantsy commented 1 week ago

@arjantijms I have tried this in the latest M8, and I found the Optional evaluation in Faceslet is a little different from the ElProcessor in expressly.

https://github.com/eclipse-ee4j/mojarra/issues/5531