Eu tenho um bean ConversationScoped, ClientController, onde tenho um objeto cliente e telefone para serem cadastrados com objetivo de serem utilizados na abertura de uma ordem de serviço, quando vou cadastrar um novo cliente posso cadastrar um ou mais telefones para esse cliente. Para isso utilizei o escopo de conversação, para o bean não perder seu estado. Porém a cada requisição está sendo executado o @PostConstruct do bean e fazendo perder o estado anterior dele, mesmo eu começando a conversação na primeira adição do telefone.
A princípio, achei que fosse problema na configuração do bean porém quando retirei um template que era usado na página ele voltou a se comportar como esperado. Esse template faz uso de um bean com escopo de sessão, que é utilizado para controlar a linguagem que será utilizado pelo cliente, português ou inglês, para aplicar a internacionalização.
Segue os fontes que acho que podem ser relevantes para a solução do problema. Se quiser dar uma olhado no projeto completo é só seguir o link do repositório github: GitHub.
ClientController.java
`
package br.com.codeshare.controller;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.inject.Produces;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import br.com.codeshare.enums.ErrorCode;
import br.com.codeshare.exception.BusinessException;
import br.com.codeshare.model.Client;
import br.com.codeshare.model.Phone;
import br.com.codeshare.qualifiers.SessionMap;
import br.com.codeshare.service.ClientService;
import br.com.codeshare.service.PhoneService;
import br.com.codeshare.util.WebResources;
@Named
@ConversationScoped
public class ClientController implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private FacesContext facesContext;
@Inject @SessionMap
private Map<String, Object> sessionMap;
@Inject
private ClientService clientService;
private Client newClient;
@Inject
private PhoneController phoneController;
@Inject
private PhoneService phoneService;
@Inject
private Conversation conversation;
private String filterName;
private List<Client> listClients;
private Client clientSelected;
private List<Phone> phoneToBeRemove;
@Produces
@Named
public Client getNewClient() {
return newClient;
}
@PostConstruct
public void initNewClient() {
newClient = new Client();
newClient.setTelefones(new ArrayList<Phone>());
listClients = clientService.findAll();
}
public String save() throws Exception {
try {
validatePhoneLeastOnePhoneObligatory(newClient);
clientService.save(newClient);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
initNewClient();
}catch (BusinessException e) {
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
facesContext.addMessage(null, m);
}catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,errorMessage,WebResources.getMessage("unsuccessful"));
facesContext.addMessage(null, m);
}
if(!conversation.isTransient()){
conversation.end();
}
return null;
}
public String update(Client client) throws Exception{
try {
validatePhoneLeastOnePhoneObligatory(client);
clientService.update(client,phoneToBeRemove);
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, WebResources.getMessage("register"),WebResources.getMessage("sucess_register")));
initNewClient();
}catch (BusinessException e) {
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR,WebResources.getMessage(e.getErrorCode()),"");
facesContext.addMessage(null, m);
return null;
} catch (Exception e) {
String errorMessage = getRootErrorMessage(e);
FacesMessage m = new FacesMessage(FacesMessage.SEVERITY_ERROR, errorMessage, WebResources.getMessage("unsuccessful"));
facesContext.addMessage(null, m);
return null;
}
if(!conversation.isTransient()){
conversation.end();
}
return "clients";
}
private void validatePhoneLeastOnePhoneObligatory(Client client) throws BusinessException {
if(client.getHomePhone().isEmpty() && client.getBisenessPhone().isEmpty()){
throw new BusinessException(ErrorCode.LEAST_ONE_PHONE_OBLIGATORY.getErrorCode());
}
}
private String getRootErrorMessage(Exception e) {
String errorMessage = "Registration failed. See server log for more information";
if (e == null) {
return errorMessage;
}
Throwable t = e;
while (t != null) {
errorMessage = t.getLocalizedMessage();
t = t.getCause();
}
return errorMessage;
}
public void addClientPhone() {
if(conversation.isTransient()){
conversation.begin();
}
phoneController.getNewPhone().setClient(newClient);
if (newClient.getPhones() == null) {
newClient.setTelefones(new ArrayList<Phone>());
}
newClient.getPhones().add(phoneController.getNewPhone());
phoneController.initNewPhone();
}
public void removeClientPhone(Phone phone){
if(conversation.isTransient()){
conversation.begin();
}
clientSelected.getPhones().remove(phone);
if(phoneToBeRemove == null){
phoneToBeRemove = new ArrayList<Phone>();
}
phoneToBeRemove.add(phone);
}
public void addClientPhoneOnUpdate() {
if(conversation.isTransient()){
conversation.begin();
}
phoneController.getNewPhone().setClient(clientSelected);
if (clientSelected.getPhones() == null) {
clientSelected.setTelefones(new ArrayList<Phone>());
}
clientSelected.getPhones().add(phoneController.getNewPhone());
phoneController.initNewPhone();
}
public void searchByName() {
listClients = null;
if(filterName == null){
listClients = clientService.findAll();
}
listClients = clientService.findByName(filterName);
}
public String edit(Client client) {
if(conversation.isTransient()){
conversation.begin();
}
this.clientSelected = client;
List<Phone> phoneList = phoneService.findPhoneByClientId(clientSelected.getId());
clientSelected.setTelefones(phoneList);
sessionMap.put("client", client);
return "update_client";
}
public Client getClientSelected() {
return (Client) sessionMap.get("client");
}
public String getFilterName() {
return filterName;
}
public void setFilterName(String filterName) {
this.filterName = filterName;
}
public List<Client> getListClients() {
return listClients;
}
}
Language.java
package br.com.codeshare.util;
import java.io.Serializable;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
@Named
@SessionScoped
public class Language implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private FacesContext facesContext;
@PostConstruct
public void init(){
localeCode = "pt";
countryLocaleCodeChanged();
}
private String localeCode;
public String getLocaleCode() {
return localeCode;
}
public void setLocaleCode(String localeCode) {
this.localeCode = localeCode;
}
// value change event listener
public void countryLocaleCodeChanged() {
facesContext.getViewRoot().setLocale(new Locale(localeCode));
}
}
client.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets" template="/template.xhtml">
<ui:define name="titulo">
#{label['client.title']}
</ui:define>
<ui:define name="body">
<h:form id="form">
<p:messages />
<p:fieldset legend="#{label['client.fieldset.client']}" id="client">
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="name" value="#{label['client.name']}" />
<p:inputText id="name" value="#{newClient.name}" />
<p:outputLabel for="adress" value="#{label['client.adress']}" />
<p:inputText id="adress" value="#{newClient.adress}" />
<p:fragment rendered='#{!language.localeCode.equals("en")}'>
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="homePhone_pt" value="#{label['client.homePhone']}" />
<p:inputMask id="homePhone_pt" value="#{newClient.homePhone}" mask="([telefone removido]"/>
<p:outputLabel for="bisenessPhone_pt" value="#{label['client.businessPhone']}" />
<p:inputMask id="bisenessPhone_pt" value="#{newClient.bisenessPhone}" mask="([telefone removido]"/>
</p:panelGrid>
</p:fragment>
<p:fragment rendered='#{language.localeCode.equals("en")}'>
<p:panelGrid columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="homePhone_en" value="#{label['client.homePhone']}" />
<p:inputText id="homePhone_en" value="#{newClient.homePhone}"/>
<p:outputLabel for="bisenessPhone_en" value="#{label['client.businessPhone']}" />
<p:inputText id="bisenessPhone_en" value="#{newClient.bisenessPhone}"/>
</p:panelGrid>
</p:fragment>
</p:panelGrid>
</p:fieldset>
<p:fieldset legend="#{label['client.fieldset.phone']}" id="phones">
<p:panelGrid id="phone" columns="1" styleClass="panelGrid-semBorda">
<p:outputLabel for="brand" value="#{label['phone.brand']}" />
<p:inputText id="brand" value="#{newPhone.brand}" />
<p:outputLabel for="model" value="#{label['phone.model']}" />
<p:inputText id="model" value="#{newPhone.model}" />
<p:outputLabel for="state" value="#{label['phone.state']}"/>
<p:selectOneRadio id="state" value="#{newPhone.state}">
<f:selectItems value="#{phoneStates}" var="p" itemValue="#{p}" itemLabel="#{label[p.label]}" />
</p:selectOneRadio>
<p:outputLabel for="esn" value="#{label['phone.esn']}" />
<p:inputText id="esn" value="#{newPhone.esn}" />
</p:panelGrid>
<p:commandButton value="#{label['phone.add']}" action="#{clientController.addClientPhone}" update="phoneTable phones"/>
<p:dataTable value="#{newClient.phones}" var="phone" emptyMessage="#{label['phone.notadd']}"
id="phoneTable">
<p:column headerText="#{label['phone.brand']}">
<p:outputLabel value="#{phone.brand}"/>
</p:column>
<p:column headerText="#{label['phone.model']}">
<p:outputLabel value="#{phone.model}"/>
</p:column>
</p:dataTable>
</p:fieldset>
<p:commandButton action="#{clientController.save}" value="#{label['client.save']}" update="@form"/>
</h:form>
</ui:define>
</ui:composition>
template.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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{language.localeCode}" encoding="utf-8">
<h:head>
<title>
<ui:insert name="title"/>
</title>
<link rel="stylesheet" type="text/css" href="resources/css/reset.css" />
<link rel="stylesheet" type="text/css" href="resources/css/style.css" />
<link rel="stylesheet" type="text/css" href="resources/css/fonts/font-awesome.min.css" />
</h:head>
<body>
<div class="main">
<div class="menu">
<ui:include src="/menu.xhtml" />
</div>
<div id="body">
<ui:insert name="body"/>
</div>
</div>
</body>
</f:view>
</html>
menu.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:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
<p:menubar>
<p:submenu label="#{label['menu.serviceorder']}">
<p:menuitem value="#{label['menu.serviceorder']}" url="/service-order.jsf"/>
<p:menuitem value="#{label['menu.serviceorder.new']}" url="/new-service-order.jsf"/>
</p:submenu>
<p:submenu label="#{label['menu.client']}">
<p:menuitem value="#{label['menu.client.new']}" url="/client.jsf"></p:menuitem>
<p:menuitem value="#{label['menu.clients']}" url="/clients.jsf"></p:menuitem>
</p:submenu>
</p:menubar>
<h:form class="menu_languages">
<p:selectOneMenu value="#{language.localeCode}">
<f:selectItem itemLabel="Português" itemValue="pt" />
<f:selectItem itemLabel="English" itemValue="en" />
<p:ajax listener="#{language.countryLocaleCodeChanged}" update="@all" />
</p:selectOneMenu>
</h:form>
</ui:composition>
</html>