如何解决 Target Unreachable, 'null'?

How to solve Target Unreachable, 'null'?

大家好我是 javaweb 的新手,我尝试创建我的第一个 javaweb 项目,当然是按照一些教程。但是,当调用某些操作时,我收到错误消息。有没有人可以帮忙!这是我所做的:

Person.java

package org.javaeesample.entities;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class Person implements Serializable {
    @Id @GeneratedValue
    private Long id;

    private String name;
    private int age;

    public Person(){        
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

PersonEjbDao.java

package org.javaeesample.ejbdao;

import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.javaeesample.entities.Person;

@Stateless
public class PersonEjbDao {
    @PersistenceContext
    EntityManager em;
    //private Person pers;
    public List<Person> listPerson(){
        CriteriaBuilder cb = em.getCriteriaBuilder();
        CriteriaQuery<Person> cq = cb.createQuery(Person.class);
        Root<Person> person = cq.from(Person.class);
        cq.select(person);
        return em.createQuery(cq).getResultList();
     }

    public Person findPerson(long pid){
        return em.find(Person.class, pid);
    }

    public void createPerson(Person pers){
        Person p = new Person();
        p.setName(pers.getName());
        p.setAge(pers.getAge());
        em.persist(p);
    }
}

FriendBean.java

package org.javaeesample.jsf;

import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;
import org.javaeesample.ejbdao.PersonEjbDao;
import org.javaeesample.entities.Person;

@Named(value = "personBean")
@RequestScoped
public class PersonBean {
    private Person person;
    private Long pid;
    private List<Person> listPerson;
    @Inject
    PersonEjbDao personDao;

    public List<Person> getPersons(){
        if (listPerson==null) {
            listPerson = personDao.listPerson();
        }
        return listPerson;
    }

    public void personDetails(){
        person = new Person();
        person = (Person) personDao.findPerson(pid);
    }

    public void createPerson(){
        personDao.createPerson(person);
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }

    public Long getPid() {
        return pid;
    }

    public void setPid(Long pid) {
        this.pid = pid;
    }

}

show.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:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
    <body>

        <ui:composition template="./WEB-INF/template.xhtml">

            <ui:define name="content">
                <h:form>
                <h:dataTable value="#{personBean.persons}" var="p">
                    <h:column>
                        <f:facet name="header">Name</f:facet>
                        <h:link value="#{p.name}" outcome="details">
                            <f:param name="pid" value="#{p.id}"/>
                        </h:link>
                    </h:column>

                    <h:column>
                        <f:facet name="header">Age</f:facet>
                        #{p.age}
                    </h:column>
                </h:dataTable>

                <h:commandButton id="create" action="create" value="Create"/>
                </h:form>
            </ui:define>

        </ui:composition>

    </body>
</html>

create.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:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:h="http://xmlns.jcp.org/jsf/html">

    <body>

        <ui:composition template="./WEB-INF/template.xhtml">

            <ui:define name="content">
                <h:form>
                    <h:panelGrid columns="3"
                             captionClass="rightalign,leftalign,leftalign">
                        <h:outputLabel value="Name:" for="name"/>
                        <h:inputText id="name" label="Name"
                                 required="true"
                                 value="#{personBean.person.name}"/>
                        <h:message for="name"/>
                        <h:outputLabel value="Age:" for="age"/>
                        <h:inputText id="age" label="Age"
                                 size="2"
                                 value="#{personBean.person.age}"/>
                        <h:message for="age"/>
                        <h:commandButton id="save" value="Save"
                                     action="list" actionListener="#{personBean.createPerson}"/>
                    </h:panelGrid>
                </h:form>
            </ui:define>
        </ui:composition>

    </body>
</html>

details.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:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:h="http://xmlns.jcp.org/jsf/html">

    <body>

        <ui:composition template="./WEB-INF/template.xhtml">
            <ui:define name="content">
                <f:metadata>
                    <f:viewParam name="pid" value="#{personBean.pid}"/>
                    <f:event type="javax.faces.event.PreRenderComponentEvent" listener="#{personBean.personDetails()}"/>
                </f:metadata>

                <h:form>
                    <h:panelGrid columns="2"
                             columnClasses="rightalign,leftalign,leftalign">
                        <h:outputText value="Name:"/>
                        <h:outputText value="#{personBean.person.name}" />
                        <h:outputText value="Age:"/>
                        <h:outputText value="#{personBean.person.age}"/>
                    </h:panelGrid>
                </h:form>
            </ui:define>
        </ui:composition>

    </body>
</html>  

当尝试 运行 我的项目时发生的事情是:
1. 当我从 show.xhtml

点击 link
<h:link value="#{p.name}" outcome="details">
    <f:param name="pid" value="#{p.id}"/> 
</h:link>  

它说:java.lang.NullPointerException

java.lang.NullPointerException  
    at org.javaeesample.jsf.PersonBean.personDetails(PersonBean.java:37)  
    at org.javaeesample.jsf.PersonBean$Proxy$_$$_WeldClientProxy.personDetails(Unknown Source)  
    ...  

但在 url 上显示:
http://localhost:8080/javaeesample/faces/details.xhtml?pid=1

  1. 当我点击 create.xhtml 中的 'Save' 按钮时,我收到以下错误消息:

发生错误:

/create.xhtml @18,73 value="#{personBean.person.name}": Target Unreachable,'null' returned null  

我展开 Stack Trace 并显示

javax.el.PropertyNotFoundException: /create.xhtml @18,73 value="#{personBean.person.name}": Target Unreachable, 'null' returned null  
    at com.sun.faces.facelets.el.TagValueExpression.getType(TagValueExpression.java:100)
    at com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getConvertedValue(HtmlBasicInputRenderer.java:95)

我不知道是什么让我的 personBean.person.name 无效。

非常感谢任何帮助。

既然小小不想写答案,那我就写吧。这个答案的部分基础是他的评论,内容如下:

Target Unreachable,'null' returned null : Either #{personBean.person} or #{personBean} is null. I smell person is null. You are trying to pre-populate person inside the personDetails(). Why do you initialize person using <f:event type="javax.faces.event.PreRenderComponentEvent" listener="#{personBean.personDetails()}"/>? You had better pre-populate private Person person; (and private List<Person> listPerson; which you are lazily initializing inside a getter method unnecessarily) at a better initialization place - inside a method annotated with @PostConstruct.

现在再解释一下

javax.el.PropertyNotFoundException: /create.xhtml @18,73 value="#{personBean.person.name}": 
    Target Unreachable, 'null' returned null

此错误意味着:“#{personBean.person}#{personBean} 为空(见上文)。我完全支持 Tiny,假设 person 是罪魁祸首。

根本原因是,在您用于初始化 Person 的侦听器运行时,xhtml 文件已经完全解析。在您的侦听器有机会更改 person 之前,它的属性应该已经被访问过。

这导致你的错误。对此的修复非常简单:

不要让 person 永远为空。 尽可能使用预先初始化来防止这种情况发生,并使您的 PersonBean 看起来如下所示:

@RequestScoped
public class PersonBean {
     private Person person = new Person();
     private Long pid = 0l;
     private List<Person> listPerson = new ArrayList<>();
     // carry on with your code from here

这允许您删除 getter 中的惰性初始化部分,应该可以解决您的问题。

另一种方法是(如 Tiny already mentioned in ), using a method annotated with @PostConstruct,像这样:

@PostConstruct
public void initialize() {
    this.person = (Person) personDao.findPerson(pid);
    this.personList = personDao.listPerson();
}