JSF HandleRenderException из-за исключения NullPointerException

Я пытался отобразить информацию базы данных на странице JSF с использованием Java EL, однако я возвращал следующее:

com.sun.faces.application.view.FaceletViewHandlingStrategy handleRenderException
SEVERE: Error rendering View[/customerInformation.xhtml]
java.lang.NullPointerException

И это продолжается оттуда (см. полный отчет об ошибке ниже).

Насколько я понимаю, поскольку ни одно из утверждений, которые я включил в свой код, кажется, не достигается, методы, содержащие их, фактически никогда не выполняются. Это наводит меня на мысль, что либо:

  1. Согласно моей предыдущей теме, я все еще могу неправильно использовать EL и испытывать проблемы из-за некоторого недопонимания. Возможно, я преодолел эти ошибки, но действительно ли я понял причину?
  2. Компонент или что-то, связанное с ним, никогда не инициализируется и, таким образом, вызывает исключение нулевого указателя.
  3. Мое использование тегов JSF на самом деле не выполняет то, что я пытаюсь сделать
  4. Происходит что-то еще, о чем я еще не думал и не понимал.

Некоторая информация о системе и библиотеке:

  • ЦенОС 6.5
  • Eclipse Kepler IDE для разработчиков Java EE
  • Системная библиотека JRE [java-1.7.0-openjdk-1.7.0.45.x86_64]
  • Apache Tomcat v7.0
  • Apache TomEE 1.6.0 JAX-RS
  • JSF Мохара 2.2 (javax.faces.jar)
  • log4j 1.2.17 (log4j-1.2.17.jar)

Представление: (customerInformation.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://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core">

    <h:head>
        <title>Customer Information</title>
    </h:head>

    <h:body>
        <h1>Customer:</h1>
        <h:dataTable value="#{customerBean.getFirstCustomer()}" var="cust"
            id="custTable">
            <h:column id="idCol">
                <f:facet name="header">
                    ID:
                </f:facet>
                #{cust.id}
            </h:column>

            <h:column id="firstnameCol">
                <f:facet name="header">
                    First Name:
                </f:facet>
                #{cust.firstname}
            </h:column>

            <h:column id="lastnameCol">
                <f:facet name="header">
                    Last Name:
                </f:facet>
                #{cust.lastname}
            </h:column>

            <h:column id="creditcardCol">
                <f:facet name="header">
                    Credit Card:
                </f:facet>
                #{cust.creditcard}
            </h:column>

            <h:column id="cidCol">
                <f:facet name="header">
                    CID:
                </f:facet>
                #{cust.cid}
            </h:column>

            <h:column id="addressCol">
                <f:facet name="header">
                    Address:
                </f:facet>
                #{cust.address}
            </h:column>
        </h:dataTable>
    </h:body>
</html>

Компонент поддержки (CustomerBean.java):

package customer;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import org.apache.log4j.Logger;

import customer.model.Customer;

@ManagedBean(name="customerBean", eager=true)
@SessionScoped
public class CustomerBean implements Serializable {

    private static final long serialVersionUID = 1L;

    private static transient Logger log =
            Logger.getLogger(CustomerBean.class.getName());

    private static final String DB_DRIVER = "oracle.jdbc.driver.OracleDriver";
    private static final String DB_URL = "jdbc:oracle:thin:@//localhost:1521/xe";
    private static final String DB_USER = "username";
    private static final String DB_PASS = "password";

    private Connection getConnection() {
        Connection conn = null;

        try {
            Class.forName(DB_DRIVER);
        } catch (ClassNotFoundException e) {
            log.warn("Oracle JDBC Driver not found!", e);
        }

        try {
            conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASS);
        } catch (SQLException e) {
            log.fatal("ERROR: Could not establish a connection to the database!", e);
        }

        assert(conn != null);

        return conn;
    }

    private ResultSet queryDatabase(String queryString) {
        ResultSet queryResponse = null;
        PreparedStatement query = null;

        if (queryString == null) {
            return null;
        }

        Connection databaseConnection = connect();

        try {
            query = databaseConnection.prepareStatement(queryString);
        } catch (SQLException e) {
            log.warn("Failed to prepare database query!", e);
        }

        assert(query != null);

        try {
            queryResponse = query.executeQuery();
        } catch (SQLException e) {
            log.warn("Failed to execute database query!", e);
        }

        assert(queryResponse != null);

        return queryResponse;
    }

    public Customer getFirstCustomer() {
        Customer customer = new Customer();
        ResultSet queryResponse = null;
        List<Customer> customerList = new ArrayList<Customer>();

        queryResponse = queryDatabase(
            "SELECT ID01, FIRSTNAME, LASTNAME, CREDITCARD, CID, ADDRESS FROM SCOTT.CUSTOMER_CC");

        try {
            Customer cust = new Customer();
            while (queryResponse.next()) {
                cust.setId(queryResponse.getInt("ID01"));
                cust.setFirstname(queryResponse.getString("FIRSTNAME"));
                cust.setLastname(queryResponse.getString("LASTNAME"));
                cust.setCreditcard(queryResponse.getString("CREDITCARD"));
                cust.setCid(queryResponse.getString("CID"));
                cust.setAddress(queryResponse.getString("ADDRESS"));

                customerList.add(cust);
            }
        } catch (SQLException e) {
            log.warn("Failed to build customer from query response.", e);
        }

        assert(!customerList.isEmpty());

        customer = customerList.get(0); // Arbitrarily pick the first customer

        return customer;
    }
}

В настоящее время я создал только метод public Customer getFirstCustomer(). Цель состоит в том, чтобы изменить его на метод public List<Customer> getCustomerList(), чтобы заполнить таблицу данных всей информацией о клиенте. Будет ли это возможно после того, как я решу свои проблемы?

Клиент POJO (Customer.java):

package customer.model;

public class Customer {

    private int id;
    private String firstname;
    private String lastname;
    private String creditcard;
    private String cid;
    private String address;

    // For brevity sake, the getters and setters are here (generated)
}

Теперь для журнала ошибок (я настроил PhaseListener, который добавил информацию о фазах рендеринга приложения. Вы заметите, что ошибка возникает на этапе Render Response):

2014-02-24 15:55:50,666 TRACE [http-bio-8080-exec-3] - test.debugPack.DebugPhaseListener.beforePhase 23 - Entering phase: [RESTORE_VIEW 1]
2014-02-24 15:55:50,768 TRACE [http-bio-8080-exec-3] - test.debugPack.DebugPhaseListener.afterPhase 18 - Completed phase: [RESTORE_VIEW 1]
2014-02-24 15:55:50,773 TRACE [http-bio-8080-exec-3] - test.debugPack.DebugPhaseListener.beforePhase 23 - Entering phase: [RENDER_RESPONSE 6]
Feb 24, 2014 3:55:51 PM com.sun.faces.application.view.FaceletViewHandlingStrategy handleRenderException
SEVERE: Error Rendering View[/customerInformation.xhtml]
java.lang.NullPointerException
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:225)
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:225)
    at org.apache.el.parser.AstValue.getValue(AstValue.java:173)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:185)
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
    at javax.faces.component.UIData.getValue(UIData.java:732)
    at javax.faces.component.UIData.getDataModel(UIData.java:1811)
    at javax.faces.component.UIData.setRowIndexWithoutRowStatePreserved(UIData.java:484)
    at javax.faces.component.UIData.setRowIndex(UIData.java:473)
    at com.sun.faces.renderkit.html_basic.TableRenderer.encodeBegin(TableRenderer.java:82)
    at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:869)
    at javax.faces.component.UIData.encodeBegin(UIData.java:1133)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1854)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:443)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:701)
Feb 24, 2014 3:55:51 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Faces Servlet] in context with path [/JSF_Remote_Data_Test] threw exception [null] with root cause
java.lang.NullPointerException
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:225)
    at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:225)
    at org.apache.el.parser.AstValue.getValue(AstValue.java:173)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:185)
    at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:194)
    at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:182)
    at javax.faces.component.UIData.getValue(UIData.java:732)
    at javax.faces.component.UIData.getDataModel(UIData.java:1811)
    at javax.faces.component.UIData.setRowIndexWithoutRowStatePreserved(UIData.java:484)
    at javax.faces.component.UIData.setRowIndex(UIData.java:473)
    at com.sun.faces.renderkit.html_basic.TableRenderer.encodeBegin(TableRenderer.java:82)
    at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:869)
    at javax.faces.component.UIData.encodeBegin(UIData.java:1133)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1854)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
    at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1859)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:443)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.tomee.catalina.OpenEJBValve.invoke(OpenEJBValve.java:45)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:701)
2014-02-24 15:55:51,357 TRACE [http-bio-8080-exec-3] - test.debugPack.DebugPhaseListener.afterPhase 18 - Completed phase: [RENDER_RESPONSE 6]

Я уже тестировал код JDBC в обычном проекте Java и смог подключиться и запросить базу данных, успешно отобразив вывод на консоли. Это, по крайней мере, продемонстрировало, что базовые механизмы взаимодействия, которые я использую, должны работать, что указывает на то, что я больше беспокоюсь об использовании JSF и EL.

Помимо желания лучше понять, что вызывает мою проблему и как ее исправить, я также был бы признателен за дополнительную информацию. Когда в течение жизненного цикла приложения создается экземпляр вспомогательного компонента? Нужно ли или лучше использовать метод @PostConstruct с моим bean-компонентом и для каких целей (т. е. создать поле-член для экземпляра Connection и получить его в методе пост-конструкции)? Самое главное, что делает EL, и можно ли вызвать обычный метод (не геттер или сеттер, как я пытаюсь сделать с getFirstCustomer() с помощью EL?

Большое спасибо за чтение. Я ценю любую помощь и совет!


person Paraparity    schedule 24.02.2014    source источник
comment
Создайте новый метод, который будет возвращать список, и вызовите этот метод в h:dataTable.   -  person Vasil Lukach    schedule 25.02.2014
comment
Ну да. Метод getFirstCustomer() изначально предназначен для возврата списка. вместо того, чтобы взять первый элемент списка и присвоить ему значение клиента, после цикла while он просто вернул список. Однако это также давало мне ту же ошибку. Поэтому мне нужно решить это, прежде чем двигаться дальше.   -  person Paraparity    schedule 25.02.2014


Ответы (2)


Это определенно очень грубый ответ, и я буду больше изучать причины моих результатов.

Однако, пытаясь изолировать проблемы в этом проекте, я создал новую рабочую область в Eclipse, скопировал папку проекта из другой рабочей области в новое расположение рабочей области на диске, а затем импортировал проект через Eclipse. После этого я столкнулся с некоторыми проблемами, вызванными тем, что не было настроено подключение к серверу для новой рабочей области. Это было решено путем создания нового экземпляра сервера в рабочей области с сохранением значений по умолчанию для Tomcat 7.0.

Затем я запустил свой проект и получил исключение class not found для com.sun.faces.config.ConfigureListener. Я знал, что это должно быть настроено в моем файле web.xml, поэтому я быстро внес изменения, которые удалили следующие строки.

<listener>
    <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>

из моего файла web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
        http://java.sun.com/xml/ns/javaee/web-app
public List<Customer> getCustomerList() {
        ResultSet queryResponse = null;
        List<Customer> customerList = new ArrayList<Customer>();

        queryResponse = queryDatabase(
            "SELECT ID01, FIRSTNAME, LASTNAME, CREDITCARD, CID, ADDRESS FROM SCOTT.CUSTOMER_CC");

        try {
            Customer cust = new Customer();
            while (queryResponse.next()) {
                cust.setId(queryResponse.getInt("ID01"));
                cust.setFirstname(queryResponse.getString("FIRSTNAME"));
                cust.setLastname(queryResponse.getString("LASTNAME"));
                cust.setCreditcard(queryResponse.getString("CREDITCARD"));
                cust.setCid(queryResponse.getString("CID"));
                cust.setAddress(queryResponse.getString("ADDRESS"));

                customerList.add(cust);
            }
        } catch (SQLException e) {
            log.warn("Failed to build customer from query response.", e);
        }

        assert(!customerList.isEmpty());

        return customerList;
}
0.xsd" version="3.0"> <!-- Project Name --> <display-name>mkyong test</display-name> <!-- Context Parameters --> <context-param> <param-name>javax.faces.PROJECT_STAGE</param-name> <param-value>Development</param-value> </context-param> <!-- Landing Page --> <welcome-file-list> <welcome-file>faces/index.xhtml</welcome-file> </welcome-file-list> <!-- Error Page --> <error-page> <exception-type>java.lang.Exception</exception-type> <location>/error.xhtml</location> </error-page> <!-- Servlet --> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- Servlet Mappings --> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>/faces/*</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.jsf</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.xhtml</url-pattern> </servlet-mapping> <!-- Context Parameters --> <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> <!-- Resource References --> <!-- Listeners --> <listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener> </web-app>

Я снова запустил проект, и на этот раз страница отобразилась без ошибок и даже отобразила информацию, хранящуюся в моей базе данных.

Странно то, что информация, представленная таблицей, представляет собой две строки повторяющейся информации. У меня есть два клиента, хранящиеся в базе данных, но только один из них отображается в обеих строках таблицы. Это странно, потому что я модифицировал метод getFirstCustomer(), чтобы он возвращал список клиентов, а не только клиента, как показано выше. Итак, теперь это выглядит так:

public List<Customer> getCustomerList() {
        ResultSet queryResponse = null;
        List<Customer> customerList = new ArrayList<Customer>();

        queryResponse = queryDatabase(
            "SELECT ID01, FIRSTNAME, LASTNAME, CREDITCARD, CID, ADDRESS FROM SCOTT.CUSTOMER_CC");

        try {
            Customer cust = new Customer();
            while (queryResponse.next()) {
                cust.setId(queryResponse.getInt("ID01"));
                cust.setFirstname(queryResponse.getString("FIRSTNAME"));
                cust.setLastname(queryResponse.getString("LASTNAME"));
                cust.setCreditcard(queryResponse.getString("CREDITCARD"));
                cust.setCid(queryResponse.getString("CID"));
                cust.setAddress(queryResponse.getString("ADDRESS"));

                customerList.add(cust);
            }
        } catch (SQLException e) {
            log.warn("Failed to build customer from query response.", e);
        }

        assert(!customerList.isEmpty());

        return customerList;
}

Несмотря на это, это шаг, близкий к правильной работе проекта, и, похоже, он решает проблему, о которой я изначально спрашивал.

Самое странное, что решение работало для обоих проектов в обеих рабочих областях, однако исходный проект в другой рабочей области столкнулся с некоторыми другими проблемами, которые заставляют меня поверить, что между некоторыми из моих ресурсов .jar есть конфликты. Я буду больше разбираться в этом, чтобы узнать, смогу ли я точно определить, что именно пошло не так и почему это решение работает.

Ваше здоровье!

person Paraparity    schedule 25.02.2014
comment
Проблема с повторяющимися строками заключается в том, что в методе getFirstCustomer(), который теперь лучше называть getCustomerList(), объект клиента был инициализирован вне цикла while. Итак, в цикле while я использовал ту же ссылку на объект для добавления новых данных в список, перезаписывая старые данные. Эта проблема решается путем перемещения строки Customerr cust = new Customer() в цикле while. - person Paraparity; 25.02.2014

Я не уверен, что это будет полезно для вас, но может помочь другим. У меня была такая же проблема, вызванная комментарием EL:

        <!-- <ul class="topMenu">
            <li><p:link outcome="/pages/dashboard.xhtml" value="Dashboard"/></li>
            <li><p:commandLink action="tickets" value="Tickets"/></li>
            <li><p:commandLink action="#{navigationBean.navigateToProfile()}" value="Profile"/></li>
            <li><a href="#" style="font-size:10px;">(#{sessionScope['currentUser'].id})</a>
                <p:commandLink   action="#{userBean.logout()}" value="LogOut"/></li>
        </ul> -->

Правильный способ комментирования языка выражений — использование тега <ui:remove>.

person Reynard    schedule 25.06.2014