2

I am totally new to JSF and in learning process, and I am having issues to understand whether to use CDI annotations or JSF annotation. At many places (like this), I found that we should always use CDI annotations, but it really doesn't work and my demo application only works when I use JSF annotations.

Below are examples where I am facing issue and my question is - could someone please explain if I am doing something wrong OR if with JSF I have to use JSF annotations and if this is true then I think these post (like this) are wrong. I see that in that post it is also mentioned that if it is JSF version 2.0 or greater without CDI then JSF annotation should be used, I checked my JSF version and it is JavaServer Faces Reference Implementation 2.1.20 Fri Mar 8 05:55:39 PST 2013, but I don't know whether it is with CDI or not.

Please refer my code snippet in the end.

@javax.faces.bean.ManagedBean v/s @javax.inject.Named

I found that in order to use a managed bean through EL (expression language) syntax - #{}, managed bean class can either be annotated with @javax.faces.bean.ManagedBean or with @javax.inject.Named.

Theoretically either way should work but when I am using CDI annotation then I get below exception:

javax.el.PropertyNotFoundException: //C:/E_Drive/Projects/Workspace/HakerRank/testing/WebContent/greeting.xhtml @21,42 value="#{userNumberBean.userNumber}": Target Unreachable, identifier 'userNumberBean' resolved to null
    at com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:100)
    at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:95)
    at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
    at javax.faces.component.UIInput.validate(UIInput.java:960)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
    at javax.faces.component.UIInput.processValidators(UIInput.java:698)

But when I use @javax.faces.bean.ManagedBean annotation then things work.



@javax.enterprise.context.SessionScoped v/s @javax.faces.bean.SessionScoped

Again, theoretically both should work, but if I use CDI bean then it doesn't bean a session bean and when I refresh my page then I still see ### UserNumberBean Instantiation ... in the logs (even though can I see that my browser has same JSESSION ID - Cookie: JSESSIONID=a7iC7zNgF3ddWg069Hzny6T3UvgIVrfQ0GYJf8_pzT6Y0TzYAW3c!1544639247) which suggests that a new bean instance is getting created. However, if I use javax.faces.bean.SessionScoped then everything works as expected.


greetings.xhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head>
    <title>Guess Number Facelets Application</title>
</h:head>
<h:body>
    <h:form>
        <h:graphicImage value="#{resource['images:OracleLogo.png']}"
            alt="Duke waving his hand" />
        <h2>Hi, my name is Duke. I am thinking of a number from
            #{userNumberBean.minimum} to #{userNumberBean.maximum}. Can you guess
            it?</h2>
        <p>
            <h:inputText id="userNo" title="Enter a number from 0 to 10:"
                value="#{userNumberBean.userNumber}">
                <f:validateLongRange minimum="#{userNumberBean.minimum}" maximum="#{userNumberBean.maximum}" />
            </h:inputText>
            <h:commandButton id="submit" value="Submit" action="response" />
        </p>
        <h:message showSummary="true" showDetail="false"
            style="color: #d20005;
font-family: 'New Century Schoolbook', serif;
font-style: oblique;
text-decoration: overline"
            id="errors1" for="userNo" />
    </h:form>
</h:body>
</html>

response.xhtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
    <title>Guess Number Facelets Application</title>
</h:head>
<h:body>
    <h:form>
        <h:graphicImage value="#{resource['images:OracleLogo.png']}"
            alt="Duke waving his hand" />
        <h2>
            <h:outputText id="result" value="#{userNumberBean.response}" />
        </h2>
        <h:commandButton id="back" value="Back" action="greeting" />
    </h:form>
</h:body>
</html>

UserNumberBean:

import java.io.Serializable;
import java.util.Random;

import javax.inject.Named;

@Named
@javax.enterprise.context.SessionScoped
public class UserNumberBean implements Serializable {
    private static final long serialVersionUID = 5443351151396868724L;
    Integer randomInt = null;
    Integer userNumber = null;
    String response = null;
    private int maximum = 10;
    private int minimum = 0;

    {
        System.out.println("### UserNumberBean Instantiation ...");
    }

    static{
        System.out.println("### UserNumberBean Static initialization ...");
    }

    public UserNumberBean() {
        Random randomGR = new Random();
        randomInt = new Integer(randomGR.nextInt(maximum + 1));
        // Print number to server log
        System.out.println("Duke's number: " + randomInt);
    }

    public void setUserNumber(Integer user_number) {
        userNumber = user_number;
    }

    public Integer getUserNumber() {
        return userNumber;
    }

    public String getResponse() {
        System.out.println("### userNumber: " + userNumber + " | randomInt: " + randomInt);
        if ((userNumber == null) || (userNumber.compareTo(randomInt) != 0)) {
            return "Sorry, " + userNumber + " is incorrect.";
        } else {
            return "Yay! You got it!";
        }
    }

    public int getMaximum() {
        return (this.maximum);
    }

    public void setMaximum(int maximum) {
        this.maximum = maximum;
    }

    public int getMinimum() {
        return (this.minimum);
    }

    public void setMinimum(int minimum) {
        this.minimum = minimum;
    }

}

UPDATE 1: @XtremeBiker - I am using Weblogic 12.1.2. Servlet version is 3.0 and JSP version is 2.1, so my JEE version should be >= 6, it means I should have CDI. Now, I don't know how to get the CDI version.

hagrawal
  • 12,025
  • 4
  • 33
  • 61
  • You miss to tell which server/version you are testing your code in and also the CDI version being tried. Anyway, the question shows research effort and is properly stated. – Xtreme Biker May 21 '18 at 15:20
  • "but I don't know whether it is with CDI or not"... JSF has no cdi by itself. You need to install that if you are not using a java-ee server. Please read https://stackoverflow.com/questions/30128395/identifying-and-solving-javax-el-propertynotfoundexception-target-unreachable and see if it contains helpful info – Kukeltje May 21 '18 at 15:47
  • @XtremeBiker I have updated my question with server info. – hagrawal May 21 '18 at 15:54
  • @Kukeltje I have updated my question with server info. – hagrawal May 21 '18 at 15:54
  • But did you check all the info that is in the link that I posted? – Kukeltje May 21 '18 at 18:33
  • @Kukeltje Thanks mate, got it. – hagrawal May 22 '18 at 11:29
  • Possible duplicate of [Identifying and solving javax.el.PropertyNotFoundException: Target Unreachable](https://stackoverflow.com/questions/30128395/identifying-and-solving-javax-el-propertynotfoundexception-target-unreachable) – Kukeltje May 22 '18 at 11:43

2 Answers2

2

If someone want to understand the full blown concept and reasons around this issue then refer this answer which was recommended by @Kukeltje, thanks mate.

Below is the short summary of my issue and what I have learned from this:

  • Root cause of my issue was that even though I was using javax.inject.Named annotation but it was not taking effect because I was not creating the CDI container.
  • Code fix was to include the beans.xml file in WEB-INF directory. Read this on how to configure a CDI application. So, basically what I was missing was I didn't configure the CDI, so that annotation was not taking effect.
    • On a side note, since mine was JEE 6 container so I explicitly needed beans.xml file, in JEE 7 container if any class has CDI annotations then server will automatically recognize the application as CDI application, read more here.
  • One other important thing I learned is that CDI annotations are preferred over JSF annotations (good that I identified and came across this issue otherwise I might have ended up using JSF annotations).
hagrawal
  • 12,025
  • 4
  • 33
  • 61
  • Please read the titles of all > 35 upvote JSF Q/A, quickly scan them and remember their existence (not memorize them ;-)). A good design helps a lot. E.g. http://stackoverflow.com/questions/30639785/jsf-controller-service-and-dao – Kukeltje May 22 '18 at 11:32
  • I ran into the same problem with IBM OpenLiberty and solved it by adding cdi feature to `server.xml` – kbridge4096 Mar 13 '20 at 03:30
1

A managed bean is a bean managed by JSF. This is an old technique JSF introduced when CDI had not been available. During that time, several scopes have been defined within JSF.

@javax.faces.bean.ManagedBean

@javax.faces.bean.SessionScoped

Since Jva EE 6, CDI is part of the EE version. CDI beans are not JSF specific might be used within the whole JEE ecosystem. CDI defines several scopes.

@javax.inject.Named

@javax.enterprise.context.SessionScoped

Above I grouped JSF vs. CDI annotations together. It is not possible to mix them. If you mix these annotations, your app will not run properly.

Don't use the old fashioned JSF tags anymore - the are marked as deprecated. Beginning with JSF 2.3 (JEE 8) old annotations are / will be removed.

  • 1
    Thanks for trying to help our. But I think the OP all knows this. The question is about **why** when using the cdi annotations it does not work. Your answer is in a way broad manner already here: https://stackoverflow.com/questions/11986847/java-ee-6-javax-annotation-managedbean-vs-javax-inject-named-vs-javax-faces (and effectively managed beans are beans that are managed by **A** container (JSF, CDI, Spring, Guice, ... ) So the first sentence is not really fully correct. And this is an addition too: https://stackoverflow.com/questions/7031885/how-to-choose-the-right-bean-scope – Kukeltje May 21 '18 at 20:56
  • Thank you for your time to reply and look into this issue. – hagrawal May 22 '18 at 11:30