javaee / mojarra

PLEASE NOTE: This project has moved to Eclipse Foundation and will be archived under the JavaEE GitHub Organization. After Feb. 1, 2021, the new location will be github.com/javaee/mojarra. Mojarra - Oracle's implementation of the JavaServer Faces specification
https://github.com/eclipse-ee4j/mojarra
Other
164 stars 58 forks source link

JSF Facelet can not recognize CDI beans. #4264

Open hantsy opened 7 years ago

hantsy commented 7 years ago

I am always trying to update myself to the latest Java EE specs. And two years ago, I created a ee8-sandbox project to practice the upcoming Java EE 8.

There is a Java EE 8 version JSF sample. which worked with the following when JSF 2.3 milestones was released.

  1. Java EE 7 API
  2. Glassfish 4.1.2 + JSF 2.3(copy and override the one existed in glassfish)

But in these days, it seems Glassfish v5 development becomes very active. It is really a good news for Java EE developers.

I tried to update all dependencies to the latest Java EE 8, and run this sample in Glassfish v 5.0 b17, I checked the GF shipped jars, it had been updated JSF to 2.3 and Weld to 3.0.Final.

But when I deployed my sample to GF v5, got the famous error Target Unreachable, identifier 'bean' resolved to null, JSF Facelet can not recognize CDI beans.

This error was described in details on stack overflow, https://stackoverflow.com/questions/30128395/identifying-and-solving-javax-el-propertynotfoundexception-target-unreachable, but none of them mentioned Java EE 8 and JSF 2.3.

The sample codes are almost same, only changed the Java EE APIs version and upgrade configuration file version.

Java EE 8 version: https://github.com/hantsy/ee8-sandbox/tree/master/jsf, upgraded to Java EE 8 APIs, did not work on GF v5, it was working when I changed the CDI bean-discovery-mode to all, and added @FacesConfig class to enable JSF 2.3. Java EE 7 version: https://github.com/hantsy/ee7-sandbox/tree/master/taskboard, used Java EE 7 APIs, worked well on GF v4

AndrewG10i commented 7 years ago

I have the absolutely the same issue! Vote up! Have tested on GlassFish 4.1.2, Payara 4.1.2.172, GlassFish 5 - everywhere the same error: javax.el.PropertyNotFoundException: ...... value="#{beanName.id}": Target Unreachable, identifier 'beanName' resolved to null More details posted here: https://stackoverflow.com/questions/45682309 Also, in my case only by reverting faces-config back to JSF 2.2 syntax - solve this issue.

hantsy commented 7 years ago

I have prepared a copy of codes for Java EE 7, and reverted the dependencies and configurations to Java EE 7 APIs. The codes are almost same, but it works in Java EE 7 and Glassfish v4. The difference is the Java EE version for APIs and configuration.

Java EE 7 sample: https://github.com/hantsy/ee7-sandbox/tree/master/taskboard

Quix0r commented 7 years ago

Just curious: Have you used @ManagedBean (JSF 2.0) or @Named (JSF 2.2) to give your backing bean a name? And have you used import javax.enterprise.context.*Scoped (JSF 2.2) and not deprecated javax.faces.bean.*Scoped (JSF 2.0). As a mixture of both versions don't work and is a common mistake to only change @ManagedBean to @Named.

hantsy commented 7 years ago

@Quix0r Did you check my sample codes?

I have used JSF in projects since 1.1. And when I used it within a DI container, such as Spring, Seam 2, CDI, I never used JSF built-in annotations to declare a bean. Never!

hantsy commented 7 years ago

BTW, It seems mojarra development is inactive in these months, from the Github commit logs, there are no resources on processing issues from reporters.

hantsy commented 7 years ago

@Andrew-Gr I found the some helpful info from GF issues. Maybe it clarified our confusion, but I think it is a very bad idea when I used JSF 2.3 in a Java EE 8 compatible application server, such as GF v5.

https://github.com/javaee/glassfish/issues/22094

We have to enable JSF 2.3 manually within a Java EE 8 container which has built-in JSF 2.3 support.

hantsy commented 7 years ago

I have added a ConfgirationBean as https://github.com/javaee/glassfish/issues/22094, but still does not work.

See #https://github.com/hantsy/ee8-sandbox/commit/942e1b234e7cddcb15f2c3ab7e7b941bcd65e054

AndrewG10i commented 7 years ago

@hantsy thank you for pointing out on the JSF 2.3 "activation" approach. I have seen that topic and also tried to activate JSF 2.3 according to that guide, but it didn't work for me as well.

xinyuan-zhang commented 7 years ago

Here is my config,it works properly in latest GF5

Test.java

package com.corejsf;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import java.io.Serializable;

/**
 * Created by xinyuan.zhang on 9/4/17.
 */

@Named(value ="test")
@SessionScoped
public class Test implements Serializable{

    public Test() {
    }

    public Test(String output) {
        this.output = output;
    }

    private String output;

    public String getOutput() {
        output = "abc";
        return output;
    }

    public void setOutput(String output) {
        this.output = output;
    }
}

ConfigurationBean.java

package com.corejsf;

/**
 * Created by xinyuan.zhang on 9/4/17.
 */
import static javax.faces.annotation.FacesConfig.Version.JSF_2_3;

import javax.faces.annotation.FacesConfig;

@FacesConfig(
        // Activates CDI build-in beans
        version = JSF_2_3
)
public class ConfigurationBean {

}

beans.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="all">
</beans>

faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.3"
              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
</faces-config>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app
        xmlns="http://xmlns.jcp.org/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
        version="3.1"
>
   <servlet>
      <servlet-name>Faces Servlet</servlet-name>
      <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
   </servlet>
   <servlet-mapping>
      <servlet-name>Faces Servlet</servlet-name>
      <url-pattern>/faces/*</url-pattern>
   </servlet-mapping>
   <welcome-file-list>
      <welcome-file>faces/index.xhtml</welcome-file>
   </welcome-file-list>
   <context-param>
      <param-name>javax.faces.PROJECT_STAGE</param-name>
      <param-value>Development</param-value>
   </context-param>
</web-app>

index.xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
<h:head>
   <title>Facelet Title</title>
</h:head>
<h:body>
   <h:outputText value="#{test.output}"/> <br/>
</h:body>
</html>
hantsy commented 7 years ago

@xinyuan-zhang Compared to your codes, only some difference:

  1. I used CDI 2.0, and set bean-discovery-mode to annotated.
  2. I have not set FacesServlet, it can be configured automatically in Servlet 3.0 container for a long time.
  3. I have added ConfigurationBean and also added javax.faces.ENABLE_CDI_RESOLVER_CHAIN(true) in web.xml, I am not sure if the javax.faces.ENABLE_CDI_RESOLVER_CHAIN is no use now.
hantsy commented 7 years ago

@xinyuan-zhang @Andrew-Gr Just confirmed when I changed bean-discovery-mode to all, it works.

So the issue is JSF 2.3 does not work when bean-discovery-mode is set to annotated in beans.xml, obviously it is unreasonable. @Andrew-Gr Can you verify it?

hantsy commented 7 years ago

@xinyuan-zhang Just checked my Java EE 7 version, https://github.com/hantsy/ee7-sandbox/blob/master/taskboard/src/main/webapp/WEB-INF/beans.xml, bean-discovery-mode with value annotated works well in Java EE 7(JSF 2.2, CDI 1.1).

xinyuan-zhang commented 7 years ago

@hantsy When you use bean-discovery-mode="annotated" in beans.xml, add

@FacesConfig(
        // Activates CDI build-in beans
        version = JSF_2_3
)

on your beans,for example

package com.corejsf;

import javax.enterprise.context.SessionScoped;
import javax.faces.annotation.FacesConfig;
import javax.inject.Named;
import java.io.Serializable;

import static javax.faces.annotation.FacesConfig.Version.JSF_2_3;

/**
 * Created by xinyuan.zhang on 9/4/17.
 */

@FacesConfig(
        // Activates CDI build-in beans
        version = JSF_2_3
)
@Named(value ="test")
@SessionScoped
public class Test implements Serializable{

    public Test() {
    }

    public Test(String output) {
        this.output = output;
    }

    private String output;

    public String getOutput() {
        output = "abc";
        return output;
    }

    public void setOutput(String output) {
        this.output = output;
    }
}
hantsy commented 7 years ago

@xinyuan-zhang I have added a standalone ConfigurationBean to enable CDI, if I set bean-discovery-mode="annotated" in beans.xml, it does not work.

Why I have to add @FacesConfig on each beans in my application, it is very unreasonable.

xinyuan-zhang commented 7 years ago

@hantsy It confuses me also, but when I add @FacesConfig on cdi beans, it really works properly with bean-discovery-mode="annotated". @edburns @AnghelLeonard @arjantijms @BalusC @manfredriem , does anyone can explain it?

hantsy commented 7 years ago

@xinyuan-zhang Personally I dislike use @FacesConfig to enable CDI as InejctionProvider.

The approaches in development stage was working well.

  1. faces-config.xml version to indicate the JSF version, but I think this version should only affect this config file itself, only indicates if the config xml schema is valid. A higher JSF implementations should be compatible with a lower-versioned faces-config.xml file, eg. mojarra 2.3.x should work well with faces-config.xml 2.2(version="2.2" in the namespace declaration.).
  2. Use javax.faces.ENABLE_CDI_RESOLVER_CHAIN(true) in web.xml to enable CDI as InjectionProvider, I think it should be set to true by default in a Java EE 8 application server. Set it to false explicitly only for those guys who do not want to use CDI to handle injection at the moment.

Remember nowdays all of us like the Convention over Configuration rule in project developments. Currently I migrated my sample from Java EE 7 to Java EE 8 and JSF 2.3, it should work without any modification. But I have to add more configuration to make it work, such as @FacesConfig and change bean-discovery-mode to all, it is unreasonable .

AndrewG10i commented 7 years ago

@hantsy I was able to successfully run the empty "hello world" JSF 2.3.2 app on Payara 5 with the bean-discovery-mode="all" in beans.xml and standalone ConfigurationBean , but once I am configuring my target project with the same settings - I am getting issues with CDI. Looks like adding @FacesConfig(version = FacesConfig.Version.JSF_2_3) to 'problem' beans partially solves the issue, but other exceptions comes during app deployment like:

WARN:   WELD-000146: BeforeBeanDiscovery.addAnnotatedType(AnnotatedType<?>) used for class org.glassfish.jersey.ext.cdi1x.servlet.internal.CdiExternalRequestScope is deprecated from CDI 1.1!
Warning:   The following warnings have been detected: WARNING: Parameter interceptedBean of type javax.enterprise.inject.spi.Bean<?> from private javax.enterprise.inject.spi.Bean<?> org.glassfish.soteria.cdi.LoginToContinueInterceptor.interceptedBean is not resolvable to a concrete type.

Warning:   The following warnings have been detected: WARNING: Parameter interceptedBean of type javax.enterprise.inject.spi.Bean<?> from private javax.enterprise.inject.spi.Bean<?> org.glassfish.soteria.cdi.RememberMeInterceptor.interceptedBean is not resolvable to a concrete type.

Severe:   Exception during lifecycle processing
org.glassfish.deployment.common.DeploymentException: CDI deployment failure:WELD-001408: Unsatisfied dependencies for type LocaleBean with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject private local.test.beans.PageBean._localeBean
  at local.test.beans.PageBean._localeBean(PageBean.java:0)
WELD-001475: The following beans match by type, but none have matching qualifiers:
  - Managed Bean [class local.test.beans.LocaleBean] with qualifiers [@Any @FacesConfig @Named]

Where PageBean something like:

import javax.faces.annotation.FacesConfig;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;

@Named
@ViewScoped
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class PageBean implements Serializable {
    @Inject
    private LocaleBean _localeBean;
}

And LocaleBean something like:

@Named
@SessionScoped
@FacesConfig(version = FacesConfig.Version.JSF_2_3)
public class LocaleBean implements Serializable {
    ...
}

So now I am trying to understand is it a part of the same issue discussed here, or this is something not related to this topic... P.S. all changes are done in the absolutely stable code, which works fine in JSF 2.2 mode...

EDIT 1: Okay, looks like I need to add "@FacesConfig(version = FacesConfig.Version.JSF_2_3)" to separate standalone "fresh" java class, not to the existing CDI bean.

EDIT 2: removed exception content as looks like it is not really related to the issue discussed here.

arjantijms commented 7 years ago

@hantsy

BTW, It seems mojarra development is inactive in these months, from the Github commit logs, there are no resources on processing issues from reporters.

Indeed, it's a little inactive. Not because of disinterest or anything, but simply a matter of time. I'm personally very busy with preparing Payara 5, of which we're planning to release the first alpha this week.

Especially the Mojarra 2.4 branch was hanging mid-development (I had to flush out my changes when we moved from java.net to GitHub) and it's high on my TODO level to resume that, but there are always higher level items popping up :(

hantsy commented 7 years ago

@arjantijms Understood.

Toberumono commented 7 years ago

@xinyuan-zhang, I didn't see this answered, but I had the same issue, and I worked out why adding @FacesConfig to a bean fixes the CDI issue. Essentially, in CdiExtension's collect method, it looks up all beans with the @FacesConfig annotation on them and, provided that the last bean found with that annotation has its value set to at least Version.JSF_2_3, it sets a flag on itself (CdiExtension) which is checked in a couple of places. In this case, the two important ones are the afterBean method in CdiExtension (where it is referenced as a field) and ELUtils#tryAddCDIELResolver (where it is referenced via the getter).

In CdiExtension#afterBean, it loads the CdiProducer-based implementations of the implicit JSF objects (i.e. "request", "session", etc) if the flag is true. While this does not have a direct effect on loading other beans, it is important when considering the new injection features.

Similarly, in ELUtils#tryAddCDIELResolver, it will only add the CDI BeanManager-based ELResolver if the flag is true. Thus, if the @FacesConfig annotation is not present on at least one resolved bean, the CDI BeanManager-based EL resolver is not added to the chain, and, as a result, any beans that were discovered purely through CDI annotations (i.e. those that are in the BeanManager) will not be resolved.

arjantijms commented 7 years ago

@Toberumono Your observation is correct.

The major problem is that JSF 2.3 by default runs in a pseudo JSF 2.2 mode (a kind of JSF 2.2 compatibility mode). To make it truly JSF 2.3 you need to switch it to JSF 2.3 via the @FacesConfig annotation with, indeed, version 2.3.

AndrewG10i commented 7 years ago

@arjantijms is it any plans for JSF 2.3.3 to be release in the nearest future with your latest changes on this? Thanks! Edit: ...ah, I see: JSF 2.3.3 -> Due by October 4, 2017. Okay, look forward to having it released soon! )

hantsy commented 7 years ago

I hope in Java EE 8 compatible environment(eg. Glassfish 5, it was just released) JSF 2.3 should be enabled by default, no need global @FacesConfig or adding it every beans, and also should free my CDI settings (both annotated or all discovery mode should work, in a Java EE 8 application, CDI is not just for JSF ).

And for those cases who want to use JSF 2.3 with Java EE 7 or Servlet 3.1 container, maybe @FacesConfig is an option. Currently I do not care about this case.

AndrewG10i commented 7 years ago

@hantsy first of all thank you for mentioning that GF 5 was released - I haven't noticed that! Re "JSF 2.3 enabled by default in GF 5" - are you sure about that? ) ...didn't have time to check it, will start practicing with GF5 from tomorrow by moving my apps to it.

arjantijms commented 7 years ago

@hantsy

I hope in Java EE 8 compatible environment(eg. Glassfish 5, it was just released), JSF 2.3 is enabled by default,

Unfortunately, this is not the case. In a full or web profile Java EE 8 environment the specification says that JSF should by default run into this 2.2 pseudo compatibility mode. I'm personally not a fan of this either. For Payara, but only for Payara, I may be able to make 2.3 the default.

no need global @facesconfig

Don't forget that you always need something to enable JSF. Like a FacesServlet mapping in web.xml, an (empty) faces-config.xml, or the use of any one of the JSF specific annotations.

Next to the empty faces-config.xml, the @FacesConfig annotation is one of the simplest ways to activate JSF. You can have JSF activated with that without any web.xml present.

Note also that JAX-RS needs an activating annotation as well

hantsy commented 7 years ago

Don't forget that you always need something to enable JSF. Like a FacesServlet mapping in web.xml, an (empty) faces-config.xml, or the use of any one of the JSF specific annotations.

If there is a @FacesConfig annotated class can configure JSF and replace the faces-config.xml, I think it is better.

Note also that JAX-RS needs an activating annotation as well

You mean the @ApplicationPath annotated Application class? but this class provides some custom room by overriding the methods.

omolenkamp commented 7 years ago

@arjantijms

The major problem is that JSF 2.3 by default runs in a pseudo JSF 2.2 mode (a kind of JSF 2.2 compatibility mode). To make it truly JSF 2.3 you need to switch it to JSF 2.3 via the @facesconfig annotation with, indeed, version 2.3.

~That's true for the new CDI features introduced in JSF 2.3 (in particular the way implicit objects are handled), but using plain @Named CDI beans in EL was already supported in JSF 2.2, and should therefore continue to work in JSF 2.3 without having to add @FacesConfig:~

Never mind, it looks like it -is- working as expected when a faces-config.xml with version="2.2" is used; resolving @Named beans only stops working when version="2.3" is used without also adding @FacesConfig. A bit weird (I'd expect version="2.3" to either activate the 2.3 features, or to do nothing without @FacesConfig), but workable.

hantsy commented 7 years ago

@omolenkamp When you change the version to 2.2 in faces-config.xml, all of the new features added in JSF 2.3 are worked(such as websocket, datetime, inject in converter, cdi alignment, el in facelets etc) ?

arjantijms commented 7 years ago

@Named beans only stops working when version="2.3" is used without also adding @FacesConfig. A bit weird (I'd expect version="2.3" to either activate the 2.3 features, or to do nothing without @FacesConfig), but workable.

That's because of a very unfortunate bug that somehow went unnoticed despite all the testing that we did. I fixed it here: https://github.com/javaserverfaces/mojarra/commit/9662b559a51efa9224cfcc56c1277520d3c2a8ca

Hoping to release 2.3.3 soon with the help of @ren-zhijun-oracle and @edburns . This bug causes a lot of confusion really. If you have the time, please try building 2.3.3-SNAPSHOT and see if that works for you.

arjantijms commented 7 years ago

Hi, @xinyuan-zhang just did the 2.3.3 release. You can find the notes here: https://github.com/javaserverfaces/mojarra/releases/tag/2.3.3

Thanks @xinyuan-zhang

arjantijms commented 7 years ago

@hantsy

That should definitely not have any influence. @FacesConfig is an annotation that's only read by a CDI Extension to enable a certain amount of build-in beans. Repeating it for multiple classes should have no effect. You might want to take a look at the Mojarra tests for this feature and see where it differs with your code.

hantsy commented 7 years ago

@arjantijms Thanks. Checked out the source codes of mojarra.

edburns commented 6 years ago

Please see this important message regarding community contributions to Mojarra.

https://javaee.groups.io/g/jsf-spec/message/30

Also, please consider joining that group, as that group has taken the place of the old dev@javaserverfaces.java.net mailing list.

Thanks,

Ed Burns