JSF-2.3 not finding my @Named CDI-1.2 managed bean
Asked Answered
T

1

2

Having recently upgraded to JSF 2.3 from 2.2, I noticed that @ManagedBean was deprecated, and after some research found that I should be using CDI-1.2 managed beans and the @Named annotation.

However after changing over to @Named, the JSF pages can't find the managed bean:

javax.servlet.ServletException: /index.xhtml @38,38 value="#{controller.telstraPass}": Target Unreachable, identifier 'controller' resolved to null

I am using Maven, eclipse and WebSphere Application Server liberty v16.0.0.4 No Idea what I am doing wrong, here are the relevant files:

Controller.java:

package ManagedBeans;

import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.servlet.http.Part;

import Main.FileHandler;
import Main.IBMEmployee;

@Named("controller")
@SessionScoped
public class Controller implements Serializable {

    private Part telstraCustomersFile;
    private Part terminateesFile;
    private String telstraPass;
    private String termineesPass;
    private String exception;
    private String exceptionTrace;
    private FileHandler fileHandler = new FileHandler();
    private IBMEmployee[] potentialMatches;

    public String perform()
    {
        try {
            fileHandler.process(telstraCustomersFile, terminateesFile, telstraPass, termineesPass);
            potentialMatches = fileHandler.potentialMatches;
        }
        catch (Exception ex) {
            StringWriter errors = new StringWriter();
            ex.printStackTrace(new PrintWriter(errors));
            exception = ex.toString();
            exceptionTrace = errors.toString();

            return ("errorPage.xhtml");
        }

        return ("searchExcel.xhtml");
    }

    public void setTelstraPass(String value) { telstraPass = value; }
    public String getTelstraPass() { return telstraPass; }
    public void setTermineesPass(String value) { termineesPass = value; }
    public String getTermineesPass() { return termineesPass; }
    public void setTelstraCustomersFile(Part file) { telstraCustomersFile = file; }
    public Part getTelstraCustomersFile() { return telstraCustomersFile; }
    public void setTerminateesFile(Part file) { terminateesFile = file; }
    public Part getTerminateesFile() { return terminateesFile; }
    public String getException() { return exception; }
    public String getExceptionTrace() { return exceptionTrace; }
    public IBMEmployee[] getExactMatches() { return fileHandler.exactMatches; }
    public IBMEmployee[] getPotentialMatches() { return potentialMatches; }
}

index.xhtml:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">   
      <h:head>
        <title>Termination Checklist</title>
        <h:outputScript name="js/scripts.js"/>      
        <h:outputStylesheet name="css/PageFormat.css"/>

        Created By Jerry Boyaji
        <h:graphicImage id="IBMLogo" name="images/IBM-logo.jpg"  width="101" height="48"/>
    </h:head>
    <h:body onload="enableDisableSubmitBtn()">
        <div id="ContentFrame">
            <h1>Corporate Account Termination Application (CATA)</h1>
            <h3>Excel Search: <br/> Select your spreadsheet files to upload:</h3>
            <br/>
            <br/>
            <h:form id="excelInputForm" enctype="multipart/form-data" 
                name="UploadForm" 
                method="Post">

                Telstra Spreadsheet File: 

                <br/>
                <h:inputFile
                    id="telstraCustomers" 
                    name="telstra file" 
                    size="40" 
                    value="#{controller.telstraCustomersFile}"
                    required="True"
                    onchange="enableDisableSubmitBtn()"/>

                Password if Applicable: 
                <h:inputSecret
                    id="telstraSpreadsheetPassword"
                    value="#{controller.telstraPass}"
                    label="Password if Applicable"/>

                <br/>
                <br/>

                Termination Spreadsheet File: 
                <br/>           
                <h:inputFile
                    id="terminatees" 
                    name="termination file" 
                    size="40"
                    value="#{controller.terminateesFile}"
                    required="True"
                    onchange="enableDisableSubmitBtn()" />

                Password if Applicable: 
                <h:inputSecret
                    id="termineesSpreadsheetPassword"
                    value="#{controller.termineesPass}"
                    label="Password if Applicable"/>    

                <br/>
                <br/>

                <h:commandButton 
                    id="submit"
                    value="Upload and Continue" 
                    type = "submit"
                    action="#{controller.perform}"/>

            </h:form>
        </div>
    </h:body>
</html>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
    <display-name>MainApplication</display-name>
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
    <context-param>
        <description>
        State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
    </context-param>
    <context-param>
        <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
        <param-value>resources.application</param-value>
    </context-param>
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <display-name>HTTPS Redirect Security Constraint</display-name>
        <web-resource-collection>
            <web-resource-name>MainApplication</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
</web-app>

Server.xml:

<server description="jerry's local server">

    <!-- Enable features -->
    <featureManager>
        <feature>localConnector-1.0</feature>
        <feature>websocket-1.1</feature>
        <feature>appSecurity-2.0</feature>
        <feature>cdi-1.2<feature>
        <feature>jsp-2.3</feature>
    </featureManager>

    <basicRegistry id="basic">
      <user name="admin" password="****"/>
   </basicRegistry>

   <administrator-role>
      <user>admin</user>
   </administrator-role>

    <remoteFileAccess>
        <writeDir>${server.config.dir}</writeDir>
    </remoteFileAccess>

    <!-- To access this server from a remote client add a host attribute to the following element, e.g. host="*" -->
    <httpEndpoint host="localhost" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>

    <!-- Automatically expand WAR files and EAR files -->
    <applicationManager autoExpand="true"/>

    <applicationMonitor updateTrigger="mbean"/>
    <keyStore id="defaultKeyStore" password="****"/>

    <webApplication id="MainApplication" location="MainApplication.war" name="MainApplication"/>
</server>

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>Termination-Checklist-Maven</groupId>
  <artifactId>MainApplication</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>MainApplication</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <pluginRepositories>
        <!-- Configure WASdev repository -->
        <pluginRepository>
            <id>WASdev</id>
            <name>WASdev Repository</name>
            <url>http://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/wasdev/maven/repository/</url>
            <layout>default</layout>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
            <releases>
                <enabled>true</enabled>
            </releases>
        </pluginRepository>
    </pluginRepositories>

  <build>
    <plugins>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.0.0</version>
        <configuration>
          <webXml>WebContent/WEB-INF/web.xml</webXml>
        </configuration>
      </plugin>
      <plugin>
            <groupId>com.ibm.websphere.wlp.maven.plugins</groupId>
            <artifactId>liberty-maven-plugin</artifactId> 
            <version>1.0</version>
            <configuration>
                <serverHome>/Applications/WebProfile</serverHome>
            </configuration>
      </plugin>
    </plugins>
  </build>

  <repositories>
    <!--other repositories if any-->
    <repository>
        <id>project.local</id>
        <name>project</name>
        <url>file:${project.basedir}/repo</url>
    </repository>
  </repositories>


  <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.faces</artifactId>
        <version>2.3.0</version>
    </dependency>
    <dependency>
        <groupId>javax.enterprise</groupId>
        <artifactId>cdi-api</artifactId>
        <version>1.2</version>
        <scope>provided<scope>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.16-beta2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.16-beta2</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.json</artifactId>
        <version>1.0.4</version>
    </dependency>
    <dependency>
        <groupId>javax.json</groupId>
        <artifactId>javax.json-api</artifactId>
        <version>1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml-schemas</artifactId>
        <version>3.16-beta2</version>
    </dependency>
        <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
  </dependencies>
</project>

faces-config.xml:

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

I also have an empty beans.xml file in my WEB-INF folder with my web.xml and faces-config.xml.

As far as I can see I have done everything right, I have no competing implementations of JSF or CDI, and am not using any of the scopes from the JSF packages. I have absolutely no idea why this is not working...

Thick answered 19/5, 2017 at 8:24 Comment(13)
Try to add jsf-2.2 feature, as I only see jsp-2.3.Integrate
I am using jsf-2.3 which is packaged in with my .war as you can see with my pom.xml, why would adding in a previous version fix this ? Jsp-2.3 is also required because nothing works without it ( I think because either jsf-2.3 or cdi-1.2 needs it as a provided dependency, can't remember which it was)Thick
Your application is simple enough to run with built in jsf-2.2, which is default for Java EE 7, so just for a test, you should try to remove any external jsf libs from your war, and run with provided one by the server.Integrate
Upgraded to jsf-2.3 to make use of asynchronousity and <f:websocket>, reverting to jsf-2.3 (as an external lib) @ManagedBean annotations like I had before still works as does using the jsf-2.2 default featureThick
Ahh, yes that is the problem. Only provided jsf implementation works with CDI annotations. Check these pags - CDI integration with JavaServer Faces and Using a Custom JSF implementation(Mojarra) with WebSphere Liberty Profile and WAS full Profile. So you either use CDI with provided, or JSF beans with custom.Integrate
@Integrate is right, the CDI feature provided by WAS Liberty only has intergratration with the server-provided jsf-2.0 and jsf-2.2 features.Pour
Well now that explains a lot ! Is it possible to use a custom CDI version which can work with my custom JSF ? I'm using this JSF: mvnrepository.com/artifact/org.glassfish/javax.faces/2.3.0Thick
@Gas, Is there any way at all I can get a CDI implementation that will work with my external JSF library (see above link), I now need CDI to make use of <f:websocket> which requires me to "@Inject" (provided by CDI) a javax.faces.push.PushContext. I haven't been able to find a JSF equivalent annotation for this, I have tried "@ManagedProperty"Thick
or @Pour if you have any ideas ?Thick
Just code it with standard websocket api without JSF...Integrate
@Integrate can you give me an example of a web socket API I could use ??Thick
Check this, you have sample application with description and code - WebSocket sample applicationIntegrate
Thanks for your help Gas, I'll summarise this and post it up a bit later as an answerThick
T
1

As Gas pointed out, the issue was that the inbuilt CDI feature in WAS does not work with an external JSF library.

See my post on IBM support page which confirms this.

A way to still make use of web sockets using JSF-2.2 is to use the Javax.websocket package as @Gas pointed out. However the limitation of this web socket implementation is that it is nowhere near as easy to send data contained in a SessionScoped ManagedBean to the client of that session only as it would have been using f:websocket from JSF-2.3 as I would have liked to do.

Thick answered 28/5, 2017 at 23:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.