0

After I am logged in an application, I have a data table. To simplify the question, I'll consider only one column. The page contains a data table and a button "add person". After pressing this button, it is opened a popup dialog where I have to insert the name of the person to be added. The JSF page:

<h:body>
    <p:dataTable var="pers" value="#{personView.persons}">
        <p:column headerText="Name">
            <h:outputText value="#{pers.name}" />
        </p:column>
    </p:dataTable>
    <h:form id="newPersonForm" prependId="false">
        <p:commandButton value="Add new person" type="button" onclick="PF('createPerson').show();" />
        <p:dialog header="Add person" widgetVar="createPerson" modal="true" height="150">
            <table>
                <tr>
                    <td><h:outputLabel for="newPersonName" value="Name: * " />  </td>
                    <td><h:inputText id="newPersonName" required="true" label="newPersonName" value="#{person.name}"/></td>
                </tr>
                <tr>
                    <td><h:commandButton type="submit" id="addPerson" value="Add Person" action="#{person.newPerson()}" /></td>                               
                </tr>
            </table>
        </p:dialog>  
    </h:form>
</h:body>

The Java view class for the data table:

@ManagedBean
@Component
@Lazy
@Scope("prototype")
public class PersonView {

private User loggedUser;
private List<Person> persons;

@Autowired
@ManagedProperty("#{personService}")
private PersonService personService;

@PostConstruct
public void init() {
    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
    loggedUser = (User) context.getSessionMap().get("loggedUser");
    persons = personService.getPersons(loggedUser);
}

// getters and setters

}

The Java class for model person:

@ManagedBean
@Component
@Scope("prototype")
@Lazy
public class Person implements Serializable{
private int id;
private String name;

@Autowired
@ManagedProperty("#{personService}")
private PersonService personService;

//getters and setters

public String newPerson() { 
    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
    User loggedUser = (User) context.getSessionMap().get("loggedUser");

    personService.addPerson(loggedUser, name);
    return "success";        
}

}

The service class:

@Service
@Scope("prototype")
public class PersonService {

@Autowired
private PersonDao personDao;

public List<Person> getPersons(User user) {
    return personDao.getPersons(user); // "select * from person where createdBy = ?"
}

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public void addPerson(User user, String name) {
    personDao.addPerson(user, name);
}   

}

After I am logged with the User, the list of persons is displayed correctly. In debug mode, in method init() from PersonView.java, the injected attribute "personService" is loaded correctly. The button "Add Person" is also displayed. After pressing it, the popup dialog appears. After entering the name of new person and press submit, it is thrown a NullPointerException. I put breakpoint there, and in the class Person.Java, the attribute "personService" is null. So, the linepersonService.addPerson(loggedUser, name); from Person.java throws this exception.

My question is how can I do to inject this service correctly? Or, at least, is recommended to replace the with another primeFaces tag? In other words, under the list of persons I want to put a button "Add person", which open a popup page. This popup page contains a form with the person name. After pressing "submit", I want to see this person added in database and in the data table.

I tried to apply the accepted answer from Spring JSF integration: how to inject a Spring component/service in JSF managed bean? . The problem is in PersonView, the attribute "personService" is injected correctly, and the list is loaded. When I want to add a new Person, in "p:dialog" I use the bean "Person" and in this case, "personService" is not injected.

I alos tried to put the content of "PersonView" in "Person". And also edited the JSF page to use only the bean "Person". In this case, personService.AddPerson() doesn't throw NullPointer, but after pressing submit in p:dialog, the person name is null, and the NullPointerException is thrown in personDao class.

P.S.: i am beginner with both Spring and JSF, and this application is only an exercise. So, if you have some suggestions to improve the code, I am open.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Catalin Vladu
  • 389
  • 1
  • 6
  • 17
  • I edited the question. The problem is that "personService" is injected in PersonView.java and is not injected in Person.java. – Catalin Vladu Oct 07 '19 at 09:34
  • In Person.java you don't have a `@ManagedProperty("#{personService}")` on that property while in PersonView.java you have. – Selaron Oct 07 '19 at 09:36
  • I added it (I forgot to edit in question body), but the problem still persists. – Catalin Vladu Oct 07 '19 at 09:41
  • You are somehow managing your beans twice each. The `@Component` and `@Autowired` is understood by Spring, the `@ManagedBean` and `@ManagedProperty("#{personService}")` is deprecated and understood by (old) JSF. I don't know if JSF is able to resolve `#{personService}` - if not it will be null. I also don't know which of both instances (Spring or JSF managed one) is returned from evaluation of a `#{person}` expression. This mixing (or messing) up of two bean management systems may result in arbitrary issues. – Selaron Oct 07 '19 at 09:52
  • 2
    @Selaron the problem is that OP somehow thinks that `personService.getPersons(loggedUser)` returns Spring-managed beans .. OP is just mixing business service logic into model. OP should be putting business service logic in a service class not in a model class. – BalusC Oct 07 '19 at 10:34
  • I did some changes. I moved the method newPerson() from Person.java in PersonView.java. In PersonView I added an attribute, "private Person newPerson", which is @ManagedProperty("#{newPerson}") . And in JSF page, inside , I replaced value="#{person.name}" with "value="#{personView.newPerson.name}" . This time, inside the method newPerson(), newPerson.name is null. In this moment, my question is how can I write correctly the bean in the form, in order to be recognized the name inside the method "newPerson()". – Catalin Vladu Oct 07 '19 at 20:18

0 Answers0