[RESOLVIDO] Problema com LazyInitialization, no Wildfly 10 (com as tecnologias JSF 2.2 Primefaces JPA/Hibernate)

2 respostas
java
S

Olá pessoal estou com o seguinte problema, eu tinha um projeto rodando no tomcat 8 perfeitamente e quando estava no tomcat fazia o uso do WELD para o CDI e o Hibernate com sua implementação para o JPA, nesse projeto uso o primefaces 5.3 e lanço mão de um componente do primefaces que é o dataTable e implementei a paginação por banco de dados usando o padrão do primefaces que é extendendo a classe LazyDataModel, até ai tudo funciona perfeitamente pois estou usando para controle de transação uma classe que eu criei e essa transação para ser utilizada é só anotar o método que precisa com @Transaction. O problema acontece quando migrei para o WildFly e com isso passei a usar JTA e DataSources ai a aplicação parou de funcionar devido ao fato que uma das implementações minha desse LazyDataModel é de um model chamado Agencia e esse model possui um relacionamento @ManyToOne com estratégia de carregamento Lazy com o model Banco, e é justamente ai que os erros começaram a acontecer, pois como não estou mais controlando a transação o container que está então à partir daí ele recupera minha entidade Agencia porém no atributo banco já vem dando o seguinte erro que é mostrado na imagem abaixo.

Isso está acontecendo devido ao fato de minha aplicação não mais controlar as transações e sim o container, então nesse contexto em que o container é responsável por isso alguém poderia me ajudar com esse problema mostrando como eu deveria fazer para que o Lazy funcione corretamente igual era no Tomcat 8. Abaixo seguem os arquivos relacionados na descrição do problema.

Agencia.java

`package br.com.r2soft.r2boletos.model;

import br.com.r2soft.r2boletos.util.jpa.converters.LocalDateTimeConverter;
import org.hibernate.envers.Audited;

import javax.persistence.*;

import javax.validation.constraints.NotNull;

import javax.validation.constraints.Size;

import java.io.Serializable;

import java.time.LocalDateTime;
@Entity

@Audited

@Table(name = agencias)

public class Agencia implements Serializable {
private static final long serialVersionUID = 1L;

private Long id;
private String descricao;
private String numero;
private String digitoVerificador;
private String telefoneContato1;
private String telefoneContato2;
private String pessoaContato;
private Banco banco;
private Boolean lixeira;
private LocalDateTime criado;
private LocalDateTime modificado;

@Id
@SequenceGenerator(name = "agencia_id_seq", sequenceName = "agencia_id_seq", allocationSize = 1, initialValue = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "agencia_id_seq")
public Long getId() {
	return id;
}
public void setId(Long id) {
	this.id = id;
}

@Size(max = 40)
@Column(name = "descricao", length = 40, nullable = true)
public String getDescricao() {
	return descricao;
}
public void setDescricao(String descricao) {
	this.descricao = descricao;
}

@NotNull
@Size(max = 5)
@Column(name = "numero", length = 5, nullable = false)
public String getNumero() {
	return numero;
}
public void setNumero(String numero) {
	this.numero = numero;
}

@Column(name = "digito_verificador", length = 1, nullable = true)
public String getDigitoVerificador() {
	return digitoVerificador;
}
public void setDigitoVerificador(String digitoVerificador) {
	this.digitoVerificador = digitoVerificador;
}

@Size(max = 15)
@Column(name = "telefone_contato1", length = 15)
public String getTelefoneContato1() {
	return telefoneContato1;
}
public void setTelefoneContato1(String telefoneContato) {
	this.telefoneContato1 = telefoneContato;
}

@Size(max = 15)
@Column(name = "telefone_contato2", length = 15)
public String getTelefoneContato2() {
	return telefoneContato2;
}
public void setTelefoneContato2(String telefoneContato) {
	this.telefoneContato2 = telefoneContato;
}

@Size(max = 40)
@Column(name = "pessoa_contato", length = 40)
public String getPessoaContato() {
	return pessoaContato;
}
public void setPessoaContato(String pessoaContato) {
	this.pessoaContato = pessoaContato;
}

@NotNull
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "banco_id")
public Banco getBanco() {
	return banco;
}
public void setBanco(Banco banco) {
	this.banco = banco;
}

@Column(name = "lixeira", nullable = false)
public Boolean getLixeira() {
	return lixeira;
}
public void setLixeira(Boolean ativo) {
	this.lixeira = ativo;
}

@NotNull
@Convert(converter = LocalDateTimeConverter.class)
@Column(name = "criado", nullable = false)
public LocalDateTime getCriado() {
	return criado;
}
public void setCriado(LocalDateTime criado) {
	this.criado = criado;
}

@NotNull
@Convert(converter = LocalDateTimeConverter.class)
@Column(name = "modificado", nullable = false)
public LocalDateTime getModificado() {
	return modificado;
}
public void setModificado(LocalDateTime modifiado) {
	this.modificado = modifiado;
}

@Override
public int hashCode() {
	final int prime = 31;
	int result = 1;
	result = prime * result + ((id == null) ? 0 : id.hashCode());
	return result;
}
@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
	Agencia other = (Agencia) obj;
	if (id == null) {
		if (other.id != null)
			return false;
	} else if (!id.equals(other.id))
		return false;
	return true;
}

@Override
public String toString() {
	return "Agencia [id=" + id + ", descricao=" + descricao + ", numero=" + numero + ", digitoVerificador="
			+ digitoVerificador + "Banco="+ banco + "]";
}

}`

LazyAgenciaModel.java

`package br.com.r2soft.r2boletos.repository.model.lazy;

import br.com.r2soft.r2boletos.model.Agencia;

import br.com.r2soft.r2boletos.repository.AgenciaRepository;

import org.primefaces.model.LazyDataModel;

import org.primefaces.model.SortOrder;
import java.io.Serializable;

import java.util.List;

import java.util.Map;

public class LazyAgenciaModel extends LazyDataModel implements Serializable {

private static final long serialVersionUID = 1L;

private AgenciaRepository agenciaRepository;

public LazyAgenciaModel(AgenciaRepository agenciaRepository) {
    this.agenciaRepository = agenciaRepository;
}

@Override
public List<Agencia> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
    List<Agencia> agencias = this.agenciaRepository.buscarComPaginacao(first, pageSize);
    this.setRowCount(this.agenciaRepository.quantidadeRegistros().intValue());
    return agencias;
}

}`

AgenciaBean.java

`package br.com.r2soft.r2boletos.controller.agencia;

import br.com.r2soft.r2boletos.model.Agencia;

import br.com.r2soft.r2boletos.model.Banco;

import br.com.r2soft.r2boletos.model.Conta;

import br.com.r2soft.r2boletos.repository.AgenciaRepository;

import br.com.r2soft.r2boletos.repository.model.lazy.LazyAgenciaModel;

import br.com.r2soft.r2boletos.service.AgenciaService;

import br.com.r2soft.r2boletos.service.BancoService;

import br.com.r2soft.r2boletos.service.ContaService;

import br.com.r2soft.r2boletos.util.MensagemAplicacao;

import br.com.r2soft.r2boletos.util.jsf.FacesUtil;
import javax.faces.view.ViewScoped;

import javax.inject.Inject;

import javax.inject.Named;

import java.io.Serializable;

import java.time.LocalDateTime;

import java.util.List;

@Named
@ViewScoped
public class AgenciaBean implements Serializable {

private static final long serialVersionUID = 1L;

@Inject
private BancoService bancoService;
@Inject
private AgenciaService agenciaService;
@Inject
private ContaService contaService;
@Inject
private AgenciaRepository agenciaRepository;

private Agencia agencia;
private Agencia agenciaExistente;
private Conta conta;
private String flagEditando;
private String numeroNomeBanco;
private List<Banco> bancos;
private LazyAgenciaModel lazyAgenciaModel;
private List<Agencia> agencias;

public AgenciaBean() {
    this.limpar();
}

/*************************************************************
 * GETTERS AND SETTERS
 **********************************************************/

public Agencia getAgencia() {
    return agencia;
}

public void setAgencia(Agencia agencia) {
    this.agencia = agencia;
}

public List<Banco> getBancos() {
    return this.bancos;
}

public List<Agencia> getAgencias() {
    return agencias;
}

public LazyAgenciaModel getLazyAgenciaModel() {
    return lazyAgenciaModel;
}

public String getFlagEditando() {
    return flagEditando;
}

public void setFlagEditando(String flagEditando) {
    this.flagEditando = flagEditando;
}

/*************************************************************
 * MÉTODOS DE NEGÓCIO
 **********************************************************/

public String salvar() {
    if (this.agenciaExistente != null && (this.agencia.getNumero().equals(this.agenciaExistente.getNumero()))) {
        if (this.agenciaExistente.getLixeira() != true) {
            FacesUtil.adicionarMensagemErro(MensagemAplicacao.getMensagem("agencia_existente_message", this.agencia.getNumero(), this.agencia.getBanco().getNome()));
            return "";
        }
    }
    Agencia agenciaSalvo = this.salvarPrivado();
    if (agenciaSalvo != null) {
        FacesUtil.adicionarMensagemInfo(MensagemAplicacao.getMensagem("r2boletos.salvar.editar.sucesso"));
        this.limpar();
        return "pretty:listar-agencias";
    }
    FacesUtil.adicionarMensagemErro(MensagemAplicacao.getMensagem("r2boletos.error"));
    return "";
}

public void salvarENovo() {
    this.salvar();
}

public String desativar() {
    this.agencia.setLixeira(true);
    this.agenciaService.desativar(this.agencia);
    return this.abandonarTela();
}

public String desativarListagem() {
    this.conta = this.verificarSeAgenciaEstaVinculadaAConta();
    if (this.conta != null) {
        FacesUtil.adicionarMensagemErro(MensagemAplicacao.getMensagem("agencia_erro_excluir"));
        return "";
    }else {
        this.agencia.setLixeira(true);
        this.agenciaService.desativar(this.agencia);
        this.carregarTodas();
        return "";
    }
}

/************************************************************
 * MÉTODOS UTILITÁRIOS
 **********************************************************/
public void limpar() {
    this.agencia = new Agencia();
}

public void inicializar() {
    if (this.agencia == null) {
        this.limpar();
    }
    if (FacesUtil.isNotPostBack()) {
        this.bancos = this.bancoService.listarTodos();
    }
}

public void inicializarTabela() {
    if (FacesUtil.isNotPostBack()) {
        this.carregarTodas();
    }
}

private Agencia salvarPrivado() {
    return (Agencia) this.agenciaService.salvar(this.agencia);
}

public String abandonarTela() {
    return "pretty:listar-agencias";
}

public boolean isEditando() {
    return this.agencia.getId() != null;
}

private Conta verificarSeAgenciaEstaVinculadaAConta() {
    return this.contaService.buscarPorNumeroAgencia(this.agencia.getNumero(), this.agencia.getBanco().getNumero());
}

public void buscarAgenciaCasoExista() {
    this.agenciaExistente = this.agenciaService.buscarPorNumeroAgenciaENumeroBanco(this.agencia.getNumero(), this.agencia.getBanco().getNumero());
    if (this.agenciaExistente != null) {
        if (this.agenciaExistente.getLixeira() == true) {
            this.agencia.setId(this.agenciaExistente.getId());
            this.agencia.setLixeira(this.agenciaExistente.getLixeira());
            this.agencia.setCriado(LocalDateTime.now());
        }
    }
}

private void carregarTodas() {
    this.lazyAgenciaModel = new LazyAgenciaModel(this.agenciaRepository);
}

}
`

AgenciaService.java

`package br.com.r2soft.r2boletos.service;

import br.com.r2soft.r2boletos.exception.R2BoletosException;

import br.com.r2soft.r2boletos.model.Agencia;

import br.com.r2soft.r2boletos.repository.AgenciaRepository;

import br.com.r2soft.r2boletos.util.MensagemAplicacao;

import br.com.r2soft.r2boletos.util.jsf.FacesUtil;
import javax.enterprise.context.Dependent;

import javax.inject.Inject;

import javax.inject.Named;

import javax.transaction.Transactional;

import java.io.Serializable;

import java.time.LocalDateTime;

import java.util.List;
<a class="mention" href="/u/named">@Named</a>

@Dependent

@Transactional(rollbackOn = {R2BoletosException.class})

public class AgenciaService implements Serializable {
private static final long serialVersionUID = 1L;

@Inject
private AgenciaRepository agenciaRepository;

public Object salvar(Agencia agencia) {
    agencia.setModificado(LocalDateTime.now());
    agencia.setLixeira(false);
    if (agencia.getId() == null) {
        agencia.setCriado(LocalDateTime.now());
    }
    return this.agenciaRepository.salvar(agencia);
}

public List<Agencia> listarTodos() {
    return this.agenciaRepository.carregarTudo();
}

public void desativar(Agencia agencia) {
    agencia.setModificado(LocalDateTime.now());
    this.agenciaRepository.desativar(agencia);
    FacesUtil.adicionarMensagemInfo(MensagemAplicacao.getMensagem("r2boletos.excluir.sucesso"));
}

public Agencia buscarPorNumeroAgenciaENumeroBanco(String numeroAgencia, String numeroBanco) {
    Agencia agenciaEncontrada = this.agenciaRepository.buscarPorNumero(numeroAgencia, numeroBanco);
    if (agenciaEncontrada != null) {
        if (agenciaEncontrada.getLixeira() == true) {
            return agenciaEncontrada;
        }
        FacesUtil.adicionarMensagemErro(MensagemAplicacao.getMensagem("agencia_existente_message", numeroAgencia, agenciaEncontrada.getBanco().getNome()));
        return agenciaEncontrada;
    }
    return null;
}

}
`

GenericRepository.java

`package br.com.r2soft.r2boletos.repository;

import javax.persistence.EntityManager;

import javax.persistence.PersistenceContext;

import java.io.Serializable;

import java.util.List;

public abstract class GenericRepository implements Serializable {

protected static final long serialVersionUID = 1L;

@PersistenceContext
protected EntityManager em;
private T model;

public void setModel(T model) {
    this.model = model;
}

/**
 * Salva ou atualiza um banco no banco de dados
 *
 * @param obj entidade a ser salva no banco de dados
 * @return retorna a entidade salva no banco de dados
 */
public T salvar(T obj) {
    return this.em.merge(obj);
}

/**
 * Apenas desativa uma entidade no banco de dados
 * sendo assim ela não aparece mais nas listagens para o cliente
 *
 * @param objeto a ser desativado
 * @return retorna o agencia que foi desativado
 */
public T desativar(T objeto) {
    return this.em.merge(objeto);
}

/**
 * Recupera uma entidade através ID do mesmo
 *
 * @param id o ID da entidade a ser buscada
 * @return a entidade localizada pelo ID ou null caso não encontre
 */

public T buscarPorId(Long id) {
    return this.em.find((Class<T>) this.model.getClass(), id);
}

/**
 * Carrega todos os agencias do agencia de dados
 *
 * @return a lista com todos os itens cadastrados
 */
public List<T> carregarTudo() {
    return (List<T>) this.em.createQuery("from  " + this.model.getClass().getName() + "  a where a.lixeira != true", this.model.getClass()).getResultList();
}

/**
 * Método utilizado para saber a quantidade de registros cadastradas no banco de dados
 *
 * @return a quantidade de registros cadastradas
 */
public Long quantidadeRegistros() {
    return this.em.createQuery("select count(a) from " + this.model.getClass().getName() + " a where a.lixeira != true", Long.class).getSingleResult();
}

/**
 * Faz a consulta usando paginação
 *
 * @param first    Define à partir de qual linha do banco de dados será retornado os resultados
 * @param pageSize Quantidade de resultados por página
 * @return A lista de agências  com a paginação aplicada
 */
public List<T> buscarComPaginacao(int first, int pageSize) {
    return (List<T>) this.em.createQuery("from " + this.model.getClass().getName() + " a where a.lixeira != true", this.model.getClass())
            .setFirstResult(first)
            .setMaxResults(pageSize)
            .getResultList();
}

public T buscarComPaginacaoPorNome(String nome) {
    return (T) this.em.createQuery("from " + this.model.getClass().getName() + " a where a.nome = :nome and a.lixeira != true", this.model.getClass())
            .setParameter(":nome", nome)
            .getSingleResult();
}

}
`

AgenciaRepository.java

`package br.com.r2soft.r2boletos.repository;

import br.com.r2soft.r2boletos.model.Agencia;

import javax.ejb.Stateless;

import javax.enterprise.context.Dependent;

import javax.inject.Named;

import javax.persistence.NoResultException;

import java.io.Serializable;

@Named
@Dependent
public class AgenciaRepository extends GenericRepository implements Serializable {

private static final long serialVersionUID = 1L;

public AgenciaRepository() {
    this.setModel(new Agencia());
}

public Agencia buscarPorNumero(String numeroAgencia, String numeroBanco) {
    try {
        Agencia agencia = this.em
                .createQuery("from Agencia a where a.numero =:numero and a.banco.numero =:banco", Agencia.class)
                .setParameter("numero", numeroAgencia)
                .setParameter("banco", numeroBanco)
                .getSingleResult();
        return agencia;
    } catch (NoResultException e) {
        return null;
    }
}

}
`

listar.xhtml

` <ui:composition 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
xmlns:p=“http://primefaces.org/ui
xmlns:pt=“http://xmlns.jcp.org/jsf/passthrough
xmlns:jsf=“http://xmlns.jcp.org/jsf
xmlns:r2soft=“http://xmlns.jcp.org/jsf/composite/composicao
template="/WEB-INF/template/template.xhtml">

<ui:define name="title">#{msg.agencia_titulo_listar}</ui:define>

<ui:define name="content">

	<f:metadata>
		<f:viewAction action="#{agenciaBean.inicializarTabela}" />
	</f:metadata>

	<div class="Container100 Responsive100">

		<div class="ContainerIndent">

			<div class="ShadowBox whiteback BlueBorderedBox">

				<h2 class="BigTopic">#{msg.agencia_subtitulo_listar}</h2>
				<div class="EmptyBox20"></div>

				<p:messages autoUpdate="true" id="msg" closable="true" />

				<h:form id="frm" prependId="false">

					<r2soft:botoesListagem outcomeBtnVoltar="pretty:home" outcomeBtnNovo="pretty:adicionar-agencia" />

					<div class="EmptyBox20"></div>

					<p:dataTable reflow="true" id="tbl-agencias" emptyMessage="#{msg.agencia_tabela_vazia}" rows="5" paginator="true" paginatorAlwaysVisible="false" paginatorPosition="bottom"
							value="#{agenciaBean.lazyAgenciaModel}"  var="agencia" lazy="true" rowsPerPageTemplate="5, 10, 20, 30, 40, 50, 100">

							<p:column styleClass="TexAlCenter" headerText="#{msg.agencia_coluna_banco}" sortBy="#{agencia.banco.nome}">
								<h:outputText id="agencia-banco" value="#{agencia.banco.nome}"/>
							</p:column>
							<p:column styleClass="TexAlCenter" headerText="#{msg.agencia_coluna}" sortBy="#{agencia.numero}">

								<h:outputText id="numero-digitoverificador" value="#{agencia.numero} #{not empty agencia.digitoVerificador ? - agencia.digitoVerificador : ''} " />

							</p:column>

							<p:column headerText="#{msg.agencia_coluna_referencia}" sortBy="#{agencia.descricao}">
								<h:outputText id="referencia" value="#{agencia.descricao}" />
							</p:column>

							<p:column headerText="#{msg.agencia_coluna_contato}" sortBy="#{agencia.pessoaContato}">
								<h:outputText id="pessoa-contato" value="#{agencia.pessoaContato}" />
							</p:column>

							<p:column headerText="#{msg.agencia_coluna_telefone1}" sortBy="#{agencia.telefoneContato1}">
								<h:outputText id="telefone" value="#{agencia.telefoneContato1}" />
							</p:column>

                            <p:column headerText="#{msg.agencia_coluna_telefone2}" sortBy="#{agencia.telefoneContato2}">
                                <h:outputText id="telefone2" value="#{agencia.telefoneContato2}" />
                            </p:column>

							<p:column styleClass="TexAlCenter" headerText="Ações">

								<r2soft:botoesTabela outcomeBtnVisualizar="pretty:visualizar-agencia" nomeParametroVisualizar="agencia" valorParametroVisualizar="#{agencia.id}"
									outcomeBtnEditar="pretty:editar-agencia" nomeParametroEditar="agencia" valorParametroEditar="#{agencia.id}" mensagemModalDesativar="#{msg.agencia_modal_desativar_message}"
									actionBtnExcluir="#{agenciaBean.desativarListagem}" nomeParametroExcluir="#{agencia}" alvoParametroExcluir="#{agenciaBean.agencia}"
									atualizarQuaisComponentes="msg tbl-agencias" />

							</p:column>
						</p:dataTable>

						<p:confirmDialog id="confirm-dialog-sair-tela" global="true" showEffect="fade" hideEffect="fade">
							<p:commandButton value="#{msg.btn_modal_sim}" type="button" styleClass="ui-confirmdialog-yes" icon="ui-icon-check" />
							<p:commandButton value="#{msg.btn_modal_nao}" type="button" styleClass="ui-confirmdialog-no" icon="ui-icon-close" />
						</p:confirmDialog>

				</h:form>

			</div>

		</div>

	</div>

</ui:define>

</ui:composition>`

2 Respostas

P

Prezado,

A exceção LazyInitializationException está ocorrendo porque os registros da entidade Agencia recuperados na base de dados, não estão no contexto persistente no momento da renderização da dataTable, verificando o arquivo listar.xhtml, você está apresentando o nome do Banco, “#{agencia.banco.nome}”, quando você invoca o método get do atributo Lazy, o proxy dinâmico gerado pelo Hibernate irá tentar recuperar a instância desejada, mas como já dito isso não será possível ocorrendo a exceção.

Para solucionar o problema você precisa dizer ao Hibernate que o Banco deve ser inicializado utilizando a clausula FETCH, a consulta ficará da seguinte forma:

select agencia from Agencia agencia
inner join fetch agencia.banco banco
where agencia.lixeira != ?1

Qualquer coisa estou a disposição para mais esclarecimentos.

S

Valeu @PauloMiranda pela resposta.

Criado 29 de fevereiro de 2016
Ultima resposta 1 de mar. de 2016
Respostas 2
Participantes 2