Hibernate, JPA - Problemas com relacionamento ManyToMany

56 respostas
kinks

Pessoal, travei no meu projeto (TCC), e acredito que seja por causa desse relacionamento.

Bom, vamos ao que interessa.

No projeto irei cadastrar novos perfis de usuário, onde irei escolher as permissões que o perfil terá.
Utilizo JSF, Spring Security, Hibernate, JPA e PrimeFaces.

Possuo as seguintes tabelas no banco:


--------------------PERFIL---------------------

----------ID_PERFIL----------NOME----------


-----------PERFIL_PERMISSAO--------------

------ID_PERFIL------ID_PERMISSAO------


-----------------PERMISSAO------------------

----ID_PERMISSAO-----NOME----ROLE----

Classe Perfil

@Entity
@Table(name="PERFIL")
public class Perfil implements Serializable{
	private static final long serialVersionUID = 1L;
	private int id;
	private String nome;
	private List<Permissao> permissoes;
	
	@Id
	@Column(name="ID_PERFIL")
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="NOME")
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	
	@ManyToMany
	@LazyCollection(LazyCollectionOption.FALSE)
	@JoinTable(name = "PERFIL_PERMISSAO",    
	joinColumns = { @JoinColumn(name = "ID_PERFIL", referencedColumnName="ID_PERFIL")},  
	inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO", referencedColumnName="ID_PERMISSAO")})
	public List<Permissao> getPermissoes() {
		return permissoes;
	}
	public void setPermissoes(List<Permissao> permissoes) {
		this.permissoes = permissoes;
	}
}

Acredito que é aqui onde esteja o problema, nesse relacionamento ManyToMany, pois não entendi muito bem como utilizá-lo.

Classe Permissao

@Entity
@Table(name="PERMISSAO")
public class Permissao {
	private int id;
	private String nome;
	private String role;
	
	@Id
	@Column(name="ID_PERMISSAO")
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	
	@Column(name="NOME")
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	
	@Column(name="ROLE")
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
}

Persistência Perfil

public class PerfilHIB {
	public void salvar(Perfil perfil) {
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		session.saveOrUpdate(perfil);
		tx.commit();
		session.close();
	}
	public void excluir(Perfil perfil) {
		Session session = HibernateUtil.getSession();
		Transaction tx = session.beginTransaction();
		session.delete(perfil);
		tx.commit();
		session.close();
	}

	@SuppressWarnings("unchecked")
	public List<Perfil> listar() {
		Session session = HibernateUtil.getSession();
		try {
			return session.createCriteria(Perfil.class).addOrder(Order.asc("id")).list();
		} finally {
			session.close();
		}
	}
	public Perfil consultar(int id) {
		Session session = HibernateUtil.getSession();
		try {
			Perfil perfil = (Perfil) session.get(Perfil.class, id);
			return perfil;
		} finally {
			session.close();
		}
	}
}

Perfil Managed Bean

public class PerfilMB implements Serializable{
	private static final long serialVersionUID = 1L;
	private Perfil perfil;
	private List<Perfil> perfis;
	
	
	public PerfilMB(){
		this.perfil = new Perfil();
		setPerfis(null);
	}
	
	public String listar(){
		this.perfil = new Perfil();
		this.perfis = new PerfilHIB().listar();
		return "success";
	}
	
	public String salvar(){
			if (this.perfil.getId() == 0){
				JSFMensageiro.info("Perfil incluido com sucesso!");
			}
			else{
				JSFMensageiro.info("Perfil alterado com sucesso.");  
			}
			new PerfilHIB().salvar(this.perfil);
			this.perfil = new Perfil();
			perfis = new PerfilHIB().listar();
			
			return "success";
	}
	
	public void excluir() {
		try {
			new PerfilHIB().excluir(getPerfil());
			JSFMensageiro.info("Perfil excluido com sucesso!");
		} catch (ConstraintViolationException e) {
			e.printStackTrace();
			JSFMensageiro.error("Erro inesperado ao excluir Consultor!");
		}		
		this.perfil = new Perfil();
		this.setPerfis(new PerfilHIB().listar());
	}

	public Perfil getPerfil() {
		return perfil;
	}

	public void setPerfil(Perfil perfil) {
		this.perfil = perfil;
	}
	
	public List<Perfil> getPerfis() {
		if (this.perfis == null)
			this.perfis = new PerfilHIB().listar();		
		return this.perfis;
	}

	public void setPerfis(List<Perfil> perfis) {
		this.perfis = perfis;
	}
}

Já está listando as permissões tudo corretamente, porém na hora de salvar um perfil surge o problema:

Advertência: #{perfilMB.salvar}: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entityBean.Permissao.id
javax.faces.FacesException: #{perfilMB.salvar}: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entityBean.Permissao.id
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
	at javax.faces.component.UICommand.broadcast(UICommand.java:315)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
	at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
	at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:177)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:187)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
	at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
	at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
	at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
	at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	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.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:931)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: javax.faces.el.EvaluationException: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entityBean.Permissao.id
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
	... 50 more
Caused by: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entityBean.Permissao.id
	at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:187)
	at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:341)
	at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4273)
	at org.hibernate.type.EntityType.toLoggableString(EntityType.java:507)
	at org.hibernate.type.CollectionType.renderLoggableString(CollectionType.java:193)
	at org.hibernate.type.CollectionType.toLoggableString(CollectionType.java:184)
	at org.hibernate.internal.util.EntityPrinter.toString(EntityPrinter.java:79)
	at org.hibernate.internal.util.EntityPrinter.toString(EntityPrinter.java:121)
	at org.hibernate.event.internal.AbstractFlushingEventListener.logFlushResults(AbstractFlushingEventListener.java:131)
	at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:107)
	at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
	at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1127)
	at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:325)
	at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
	at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
	at persistencia.PerfilHIB.salvar(PerfilHIB.java:19)
	at managedBean.PerfilMB.salvar(PerfilMB.java:35)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.el.parser.AstValue.invoke(AstValue.java:278)
	at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:274)
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:105)
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:88)
	... 51 more
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:164)
	... 75 more

Estou há vários dias encalhado nisso, pesquisei bastante, mas nada. Minha esperança são vocês!

Não sei se ficou claro o problema. Caso precise mostrar mais alguma coisa pra entender melhor, é só dizer.

Obrigado! =)

56 Respostas

tiago.vt

Você esta adicionando o valor correto para o id do permissão??

kinks

Desculpe, não entendi corretamente sua pergunta. Você quis dizer o nome do campo ID da PERMISSAO?
Pra ter uma visão melhor, tá aqui o form do Perfil.

<h:outputLabel value="Nome:" for="nome" />
				<p:inputText id="nome" value="#{perfilMB.perfil.nome}" label="nome" size="50" maxlength="50" required="true" >
				<p:message for="nome" update="panel"/>
				</p:inputText>

				<h:outputLabel value="Permissões:" />
				<p:selectManyCheckbox value="#{perfilMB.perfil.permissoes}" layout="pageDirection">
					<f:selectItems value="#{permissaoMB.permissoes}" var="permissao"   itemLabel="#{permissao.nome}" itemValue="#{permissao.id}" />
				</p:selectManyCheckbox>

				<f:facet name="footer">
					<p:commandButton value="Salvar" action="#{perfilMB.salvar}" />
					<p:commandButton value="Cancelar" action="#{perfilMB.listar}" immediate="true" />
				</f:facet>
kinks

Alguém? :frowning:

R

Voce esta tentando salvar uma lista ?

drsmachado

Não entendi uma coisa, me mostre onde estão os atributos identificados no referencedColumnName

@ManyToMany @LazyCollection(LazyCollectionOption.FALSE) @JoinTable(name = "PERFIL_PERMISSAO", joinColumns = { @JoinColumn(name = "ID_PERFIL", referencedColumnName="ID_PERFIL")}, inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO", referencedColumnName="ID_PERMISSAO")}) public List<Permissao> getPermissoes() { return permissoes; }
Pois eu só achei

@Id  
    @Column(name="ID_PERMISSAO")  
    public int getId() {  
        return id;  
    }  
//E
 @Id  
    @Column(name="ID_PERFIL")  
    public int getId() {  
        return id;  
    }

Ou seja, esses referencedColumnName deveriam estar assim

@ManyToMany @LazyCollection(LazyCollectionOption.FALSE) @JoinTable(name = "PERFIL_PERMISSAO", joinColumns = { @JoinColumn(name = "ID_PERFIL", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO", referencedColumnName="id")}) public List<Permissao> getPermissoes() { return permissoes; }
Ou estou errado?

kinks

Isso, quero salvar uma lista de Permissões assiciadas a um Perfil.

No banco de dados ficaria assim:

PERFIL


ID_PERFIL Nome
1 Administrador

PERMISSAO


ID_PERMISSAO Nome
1 Perm1
2 Perm2
3 Perm3

PERFIL_PERMISSAO


ID_PERFIL ID_PERMISSAO
1 1
1 2
1 3

kinks

drsmachado:
Não entendi uma coisa, me mostre onde estão os atributos identificados no referencedColumnName

@ManyToMany @LazyCollection(LazyCollectionOption.FALSE) @JoinTable(name = "PERFIL_PERMISSAO", joinColumns = { @JoinColumn(name = "ID_PERFIL", referencedColumnName="ID_PERFIL")}, inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO", referencedColumnName="ID_PERMISSAO")}) public List<Permissao> getPermissoes() { return permissoes; }
Pois eu só achei

@Id  
    @Column(name="ID_PERMISSAO")  
    public int getId() {  
        return id;  
    }  
//E
 @Id  
    @Column(name="ID_PERFIL")  
    public int getId() {  
        return id;  
    }

Ou seja, esses referencedColumnName deveriam estar assim

@ManyToMany @LazyCollection(LazyCollectionOption.FALSE) @JoinTable(name = "PERFIL_PERMISSAO", joinColumns = { @JoinColumn(name = "ID_PERFIL", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO", referencedColumnName="id")}) public List<Permissao> getPermissoes() { return permissoes; }
Ou estou errado?

Então, com ou sem esse referencedColumnName dá o mesmo erro. E do jeito que você disse também continua a mesma coisa. =/

Estou ficando louco, muito confuso esse erro.

R

Acredito que o erro esteja aqui:

if (this.perfil.getId() == 0){  
           JSFMensageiro.info("Perfil incluido com sucesso!");  
}

Voce ta passando uma lista para o save, porem ai voce pega o ID, mas nao da lista.

kinks

rof20004:
Acredito que o erro esteja aqui:

if (this.perfil.getId() == 0){  
           JSFMensageiro.info("Perfil incluido com sucesso!");  
}

Voce ta passando uma lista para o save, porem ai voce pega o ID, mas nao da lista.

Desculpe, acho que não expliquei direito. ^^
Estou querendo salvar apenas um Perfil, onde neste Perfil contêm uma lista de Permissões.

R

Ahhhhh…desculpa, heheheh.

Bom, no meu caso, vo da uma pesquisada aqui, se encontrar alguma discrepancia lhe aviso, ate mesmo porque to comecando agora em JSF.

Flw e boa sorte.

M

Velho coloca o ID do tipo integer, testa e manda o erro devolta o relacionamento ao meu ver está correto.

kinks

Mas todos os IDs já são do tipo int.

Ou você quis dizer outra coisa?

M

Não eles estão do tipo int, e não do tipo da classe Integer, coloca ai Integer id, e renova os métodos get and set dele

M

É padrão e ja li em alguns lugares que o tipo do ID tem que ser integer, você está utilizando JPQL no applicatonContext-security.xml para fazer a validação de quem tem determinada permissão, não é? Se sim passe essa JQPL para que possamos analisar.

kinks

Desculpe a ignorância. ^^
Pra mim era tudo a mesma coisa.
Eu sempre utilizei int ou long, e nunca tive problemas.

Fiz do jeito que você disse e ganhei um NullPointerException:

Dez 24, 2012 4:29:21 PM com.sun.faces.renderkit.html_basic.HtmlBasicRenderer getForComponent
Advertência: Não foi possível encontrar o componente com a ID permissoes na exibição.
Dez 24, 2012 4:29:24 PM com.sun.faces.lifecycle.InvokeApplicationPhase execute
Advertência: #{perfilMB.salvar}: java.lang.NullPointerException
javax.faces.FacesException: #{perfilMB.salvar}: java.lang.NullPointerException
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:118)
	at javax.faces.component.UICommand.broadcast(UICommand.java:315)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
...

Caused by: javax.faces.el.EvaluationException: java.lang.NullPointerException
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
	... 50 more
Caused by: java.lang.NullPointerException
	at managedBean.PerfilMB.salvar(PerfilMB.java:29)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...

Aí, só para testar, fiz essas alterações no Método salvar do Managed Bean Perfil:
Antes:

public String salvar(){	
			if (this.perfil.getId() == 0){
				JSFMensageiro.info("Perfil incluido com sucesso!");
			}
			else{
				JSFMensageiro.info("Perfil alterado com sucesso.");  
			}
			new PerfilHIB().salvar(this.perfil);
			this.perfil = new Perfil();
			perfis = new PerfilHIB().listar();
			return "success";
	}

Despois:

public String salvar(){	
			new PerfilHIB().salvar(this.perfil);
			this.perfil = new Perfil();
			perfis = new PerfilHIB().listar();
			return "success";
	}

E então voltou o mesmo erro:

Advertência: #{perfilMB.salvar}: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entityBean.Permissao.id
javax.faces.FacesException: #{perfilMB.salvar}: org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of entityBean.Permissao.id

Complicado né?

Obrigado por estar me ajudando.

kinks

Aqui está o JPQL do aplicationContext.xml

<sec:authentication-manager>
	    <sec:authentication-provider>
	    <!--<sec:password-encoder hash="md5"/>-->
	        <sec:jdbc-user-service data-source-ref="dataSource"
	            users-by-username-query="SELECT LOGIN, SENHA, 'true' as enable FROM USUARIO WHERE LOGIN=?"
	            authorities-by-username-query="SELECT U.LOGIN, P.ROLE FROM USUARIO U
												inner join perfil_permissao PP
												on U.ID_PERFIL=PP.ID_PERFIL
												inner join permissao P
												on PP.ID_PERMISSAO=P.ID_PERMISSAO
												WHERE LOGIN=?;" />
	    </sec:authentication-provider>
	</sec:authentication-manager>
M

Então amigo o seu objeto está indo sem um ID, no seu formulário coloca,
<h:inputHidden value="#{bean.propriedade.id}"/>

Só pra ve se vai continua retornando null pointer

kinks

Fiz isso e volta o mesmo erro: occurred calling getter of entityBean.Permissao.id

O ID da classe Perfil está com a seguinte annotation:

@GeneratedValue(strategy=GenerationType.AUTO)

Já está gerando automaticamente o ID. Será que isso está influenciando? (Apesar de dar na mesma com ou sem isso)

:s

M

È estranho ajudar um código que é diferente do modo como eu relaciono, mas coloque o inverseColumn dessa maneira, não há necessecidade doo referenced:

joinColumns = @JoinColumn(name = “DonaDaChave”), inverseJoinColumns = @JoinColumn(name = “NaoDona”)

Outra coisa coloque a annotation emcima da propriedade

EX:

@ID
@GeneratedValue
private integer ID;

private Integer getId(){}

private void setId(Integer id){}

kinks

Perae, eu não precisaria especificar assim não?
Tipo:
O nome das chaves primárias das tabelas pai.
Que no caso seriam ID_PERFIL e ID PERMISSAO:

PERFIL


ID_PERFIL Nome
1 Administrador

PERMISSAO


ID_PERMISSAO Nome
1 Perm1
2 Perm2
3 Perm3

O nome das chaves estrangeiras que estão na tabela filho.
Que no caso também seriam ID_PERFIL e ID PERMISSAO:

PERFIL_PERMISSAO


ID_PERFIL ID_PERMISSAO
1 1
1 2
1 3

Do jeito que estava já funcionava a listagem de Perfis e das Permissões, só na hora de incluir um novo Perfil que dá o problema.

Fiquei confuso. Desculpe se não fui claro.

M

Você fez a alteração que eu falei acima?

kinks

Sim, coloquei as annotations em cima dos atributos, mas não faz diferença.

Já na parte do relacionamento está assim:

joinColumns = { @JoinColumn(name = "ID_PERFIL")},    
    inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO")})

É nisso que estou confuso, do jeito que você disse ficaria assim:
joinColumns = { @JoinColumn(name = “ID_PERFIL”)}, inverseJoinColumns={@JoinColumn(name=“ID_PERFIL”)})

Mas e onde entraria o ID_PERMISSAO?

M

Velho para que vc quer numerar a permissão?? Veja o relacionamento que fiz abaixo, aqui acontece o seguinte o relacionamento pega o id do usuario joga pra tabela do nessa tabela existe uma role pra esse usuario ponto final.

package financeiro.usuario;

import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.*;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Table(name= "usuario")
public class Usuario implements Serializable{

	private static final long serialVersionUID = -7390392097656238443L;
	
	@Id
	@GeneratedValue
	private Integer codigo;
	private String nome;
	private String email;
	@org.hibernate.annotations.NaturalId
	private String login;
	private String senha;
	private Date nascimento;
	private String celular;
	private String idioma;
	private boolean ativo;
	
	//relação pai e filho
	//necessario para informar o tipo de dado da hashset.
	@ElementCollection(targetClass = String.class)
	@JoinTable(
			name="usuario_permissao",
			uniqueConstraints = {@UniqueConstraint(columnNames = {"usuario", "permissao"})},//constroi um indice unico entre as colunas usuario e permissao
			joinColumns = @JoinColumn(name = "usuario"))//diz a qual coluna da tabela filho a tabela pai vai se ligar
	@Column(name = "permissao", length=50)
	private Set<String> permissao = new HashSet<String>();
	
	public Integer getCodigo() {
		return codigo;
	}
	public void setCodigo(Integer codigo) {
		this.codigo = codigo;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getLogin() {
		return login;
	}
	public void setLogin(String login) {
		this.login = login;
	}
	public String getSenha() {
		return senha;
	}
	public void setSenha(String senha) {
		this.senha = senha;
	}
	public Date getNascimento() {
		return nascimento;
	}
	public void setNascimento(Date nascimento) {
		this.nascimento = nascimento;
	}
	public String getCelular() {
		return celular;
	}
	public void setCelular(String celular) {
		this.celular = celular;
	}
	public String getIdioma() {
		return idioma;
	}
	public void setIdioma(String idioma) {
		this.idioma = idioma;
	}
	public boolean isAtivo() {
		return ativo;
	}
	public void setAtivo(boolean ativo) {
		this.ativo = ativo;
	}
	public Set<String> getPermissao() {
		return permissao;
	}
	public void setPermissao(Set<String> permissao) {
		this.permissao = permissao;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (ativo ? 1231 : 1237);
		result = prime * result + ((celular == null) ? 0 : celular.hashCode());
		result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());
		result = prime * result + ((email == null) ? 0 : email.hashCode());
		result = prime * result + ((idioma == null) ? 0 : idioma.hashCode());
		result = prime * result + ((login == null) ? 0 : login.hashCode());
		result = prime * result
				+ ((nascimento == null) ? 0 : nascimento.hashCode());
		result = prime * result + ((nome == null) ? 0 : nome.hashCode());
		result = prime * result
				+ ((permissao == null) ? 0 : permissao.hashCode());
		result = prime * result + ((senha == null) ? 0 : senha.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;
		Usuario other = (Usuario) obj;
		if (ativo != other.ativo)
			return false;
		if (celular == null) {
			if (other.celular != null)
				return false;
		} else if (!celular.equals(other.celular))
			return false;
		if (codigo == null) {
			if (other.codigo != null)
				return false;
		} else if (!codigo.equals(other.codigo))
			return false;
		if (email == null) {
			if (other.email != null)
				return false;
		} else if (!email.equals(other.email))
			return false;
		if (idioma == null) {
			if (other.idioma != null)
				return false;
		} else if (!idioma.equals(other.idioma))
			return false;
		if (login == null) {
			if (other.login != null)
				return false;
		} else if (!login.equals(other.login))
			return false;
		if (nascimento == null) {
			if (other.nascimento != null)
				return false;
		} else if (!nascimento.equals(other.nascimento))
			return false;
		if (nome == null) {
			if (other.nome != null)
				return false;
		} else if (!nome.equals(other.nome))
			return false;
		if (permissao == null) {
			if (other.permissao != null)
				return false;
		} else if (!permissao.equals(other.permissao))
			return false;
		if (senha == null) {
			if (other.senha != null)
				return false;
		} else if (!senha.equals(other.senha))
			return false;
		return true;
	}
	
}

Observe que só precisa de um relacionamento, coloque do jeito que falei e me mostre o erro novamente.

kinks

Desculpe, não entendi do jeito que você disse.
E para não ficar te perguntando sobre isso, fiquei fazendo uns testes. E então descobri que o relacionamento que estou fazendo está funcionando perfeitamente.

Chegamos a um avanço, o que fiz foi o seguinte:

No método salvar, inseri manualmente o ID do PERFIL e o ID de uma PERMISSAO. E veja só, funcionou! =D

public String salvar(){	
             //Inserindo manualmente:
			perfil.setId(6);
			Permissao permissao = new Permissao();
			permissao.setId(1);
			List <Permissao> perms = new ArrayList<Permissao>(); 
			perms.add(permissao);
			perfil.setPermissoes(perms);
              //.
	        if (this.perfil.getId() == 0){  
	            JSFMensageiro.info("Perfil incluido com sucesso!");  
	        }  
	        else{  
	            JSFMensageiro.info("Perfil alterado com sucesso.");    
	        }  

			new PerfilHIB().salvar(this.perfil);
			this.perfil = new Perfil();
			perfis = new PerfilHIB().listar();
			return "success";
	}

Então o problema é que os ids estão chegando vazios.
Tu poderia checar o meu formulário de inserção/Alteração de Perfil? Não consegui encontrar nada de errado nele. (Foi postado mais no início)
Será que pode ser algum problema também com o Converter?

Valeu cara!

M

Velho você lembra daquela linha no formulário que eu falei que vc teria que colocar para alimentar o id do perfil??

<h:inputHidden value="#{UsuarioBean.usuario.codigo}"/>

Esse código parece inútil a primeira vista mais depois você vai ver que ele está ativando a propriedade pelo set e então o método set usara a propriedade e então a annotation entrara em ação gerando um valor.

kinks

Mathe:
Velho você lembra daquela linha no formulário que eu falei que vc teria que colocar para alimentar o id do perfil??

<h:inputHidden value="#{UsuarioBean.usuario.codigo}"/>

Esse código parece inútil a primeira vista mais depois você vai ver que ele está ativando a propriedade pelo set e então o método set usara a propriedade e então a annotation entrara em ação gerando um valor.

Agora dá o seguinte erro:

org.hibernate.PropertyAccessException: could not get a field value by reflection getter of entityBean.Permissao.id
..........

Caused by: java.lang.IllegalArgumentException: Can not set int field entityBean.Permissao.id to java.lang.String

Está dizendo que não existe o getId da Permissao, correto? Mas ele está lá. =/

M

Agora só esta dando o seguinte erro quando a gente pega o valor, da pagina jsf no caso ele esta indo como string mas a propriedade e int. Mas agora esta tudo quase certo só falta a gente conseguir ajeitar essa inserção

M

Como está a propriedade id e seus getters e setters? No banco de dados como está a coluna int? está para receber numeros inteiros ou caracteres?

kinks

No banco o ID é do tipo int.

Na classe Permissao, já testei o ID como int e Integer. Acontece o mesmo.

M

Analisa o caminho que o ID está fazendo desde que vc cilca em salvar até chegar no banco e ve se em alguma parte desse caminho o id está sendo colocado em uma propriedade string

kinks

Observei com o debug e nada.

To pensando que pode ser algo relacionado com o converter. Apesar de já ter utilizado desta maneira, dá uma olhada aí:

public class PermissaoConverter implements Converter {
	public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
		if (value == null)
			return null;
		return new PermissaoHIB().consultar(Integer.parseInt(value));
	}

	public String getAsString(FacesContext context, UIComponent component, Object object) throws ConverterException {
		if (object == null)
			return null;
		Permissao permissao = (Permissao) object;
		return Integer.toString(permissao.getId());
	}
}

Tenso…

M

Relacionado ao converter não pode ser por que o converter trata o objeto inteiro e não só a propriedade, além do no erro esta especificando que a entrada de um argumento errado está vindo do id, faz assim ó pega o id que está entrando no objeto com o código <h:inputHidden que eu te mandei lembra?? Então esse código esta alimentando o id do objeto antes de salvar esse objeto recupere o id e faça a conversão de String para Integer.

kinks

Veja só o que descobri.
O formulário está mandando uma lista de permissões vazias. '.'
Para fazer alguns testes, no método salvar fiz assim:
perfil.getPermissoes().size (E retorna o número de permissões que escolhi no formulário)
E depois fiz um foreach pra correr a lista inteira e imprimir o que tinha, mas não imprime nada.

Muito curioso. :?

M

LOL velho achei o problema está aqui ó, itemValue="#{permissao.id}" tira isso só da sua view cara, agora ficou claro por que está dando erro de tentativa de conversão inesperada hahaha.

kinks

Pior que não, tirei e dá o mesmo erro. Tentei também assim itemValue="#{permissao}" e não deu.

Acrescentando…
O estranho é que sempre aparece isso:

M

Tem algum componente na sua página xhtml com o id permissoes?

kinks

Não, a única parte que tem uma lista de permissões é no select:

<p:selectManyCheckbox value="#{perfilMB.perfil.permissoes}" layout="pageDirection">
					<f:selectItems value="#{permissaoMB.permissoes}" var="permissao"   itemLabel="#{permissao.nome}"/>
				</p:selectManyCheckbox>
M

Me diz uma coisa mesmo depois de vc ter tirado o itemValue="#{permissao.id} ele continuou dando o erro :

org.hibernate.PropertyAccessException: could not get a field value by reflection getter of entityBean.Permissao.id  
..........  
  
Caused by: java.lang.IllegalArgumentException: Can not set int field entityBean.Permissao.id to java.lang.String
kinks

Sim, exatamente o mesmo. =/

M

velho vc colocou o seu converter na página xhtml?

<f:converter converterId=“userConverter”/>

o que está escrito no atributo converterId acima no caso userConverter vc deve definir na annotation, @FacesConverter(value=“userConverter”)

senão colocou ele deveria ficar tag SelectManyCheckbox abaixo da tag <f:selectItems>

Vou ir pra casa agora e vou ver se precisa colocar esse converter no web.xml também.

kinks

Pensei que não precisaria, visto qua já adicionei o converter no faces-config.xml
No entanto, já tinha tentado colocar no formulário como você disse e dá uma exception:

Editado:
Calma aí, deu essa exception porque eu tinha colocado de volta aquele itemValue="#{permissao.id}"

Tirei ele e agora não deixa salvar devido algum erro de validação, vou dar mais uma checada e retorno aqui.

M

kinks:
Pensei que não precisaria, visto qua já adicionei o converter no faces-config.xml
No entanto, já tinha tentado colocar no formulário como você disse e dá uma exception:

Estamos ficando sem opções. :frowning:

AAAA vc já tinha configurado lá então acontece o seguinte velho, o seu itemValue era um id lembra que pedi pra vc tirar do formulário algo como: itemValue="#{permissao.id}" então esse id é um inteiro e ele está indo para um argumento do método convert que aceita Strings, esse é o erro tente mudar o parametro do método converter para receber o value como, Integer value.

Mesmo assim vc tem que colocar <f:converter> para saber qual converter está sendo utilizado naquela situação.

kinks

Tá loco, um erro atrás do outro. :shock:

Agora quando vou incluir um novo Perfil o formulário retorna o seguinte: "j_idt10:j_idt16: Erro de validação: o valor não é válido."
Se eu apenas dar um nome ao Perfil sem escolher permissões, ele salva.
E então pensei que poderia ser o charset do banco, visto que as palavras com ascento estavam “bagunçadas”.
Aí mudei o charset do banco para latin1 - pois é o que está definido em minhas páginas.
Agora os ascentos estão aparecendo corretamente, mas o erro de validação persiste.
O mais estranho é que a mensagem fala de dois componentes “j_idt10” e “j_idt16”. Inspecionei com o Firefox e existe apenas o “j_idt10” - que é o meu form. Já esse “j_idt16” não existe (componente fantasma rsrs). :shock:

E outra, quando vou alterar um perfil dá o seguinte erro no log:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection, could not initialize proxy - no Session

Cansei… :x

M

A annotation lazy não é necessaria é visto que o carregamento de dados do banco não é muito significativo, retire e vamos ver se fica só o outro erro.

M

Velho vamos descomplicar se o problema está ai, pega e da uma permissão de usuario normal para cada usuário novo cadastrado e então depois se ele precisar de uma permissão de administrador ou de desenvolverdor vc da com um usuario administrador que vc pode dar permissão de administrador pelo banco para o 1º usário.

kinks

Sem a annotation dá o mesmo erro:

failed to lazily initialize a collection of role: entityBean.Perfil.permissoes, could not initialize proxy - no Session

Então cara, se pudesse já teria deixado isso de lado, além disso, no projeto existem diversos outros casos semelhantes a este. Se isso não funfar meu projeto fica parado. =/

M

Sei la velho é seu tcc não é? Não tem ninguém pra te auxilia na persistencia, eu nem minha faculdade não começei ainda só vai começar ano que vem =| , entra nesse blog www.uaihebert.com.br e lê o mini livro dele sobre JPA é mt bom.

kinks

Ter até tem uns caras, mas ficam com preguiça de ajudar, aí também não fico correndo atrás e tento me virar sozinho.
Vou continuar pesquisando e ler esse mini livro.

Cara, brigadão pela ajuda, mesmo!

kinks

Finalmente, foi resolvido grande parte dos problemas! :smiley:
Vamos lá!

O problema de “Erro de validação: o valor não é válido” era apenas meus métodos sobrescritos, hashCode() e equals() que estavam errados. Peguei outro modelo e pronto.
(Fonte: http://www.rponte.com.br/2008/02/01/selectonemenu-converter-erro-de-validacao/)

Depois disso, ele ainda não gravava por causa da annotation “errada”, ou melhor, invertida:
Errado:

joinColumns = { @JoinColumn(name = "ID_PERMISSAO")},    
    inverseJoinColumns={@JoinColumn(name="ID_PERFIL")})

Correto:

joinColumns = { @JoinColumn(name = "ID_PERFIL")},    
    inverseJoinColumns={@JoinColumn(name="ID_PERMISSAO")})

Depois dessas alterações a inclusão de Perfil está funcionando corretamente.
Agora tenho apenas um erro quando vou alterar um Perfil:

Ainda sim já senti um alívio. :slight_smile:

Ah, só pra informar, para gerar os IDs automaticamente não é necessário inserir o inputHidden no formulário. <h:inputHidden value="#{UsuarioBean.usuario.codigo}"/>

kinks

Alguém aí que já tenha passado por isso? (LazyInitializationException)

Parece ter algo haver com o Spring. :?

M

me mostra seus relacionamentos, tem algum relacionamento que busca uma lista e não é qualquercoisaToOne?

@LazyCollection(LazyCollectionOption.FALSE) retira isso da sua classe e perfil, essa exceção ocorre quando vc faz o que? Se for quando vc faz alguma pesquisa, poste suas classes DAO.

kinks

Por enquanto, o único relacionamento que tenho mesmo é esse ManyToMany, entre Perfil e Permissão.

O erro ocorre quando vou alterar um Perfil.
Tipo assim:
Na página tenho uma lista de Perfis, seleciono um para alterar, aparece a página de alteração, modifico algo, e quando clico em salvar acontece a exception.

Sem a annotation (@LazyCollection(LazyCollectionOption.FALSE)) fica pior, a exception acontece antes de exibir a página de alteração.

Com a annotation a exception é assim:

Sem a annotation a exception é assim:

Se precisar, minha classe de Persistência de Perfil está na primeiro post, o nome da classe é: PerfilHIB.

M

Então velho no seu relacionamento ManyToMany faça o seguinte @ManyToMany(fetch=FetchType.EAGER) isso deve mudar a forma com que ele pega os dados do banco.

kinks

Já tentei isso e dá a mesma exception. =/

M

http://blog.caelum.com.br/enfrentando-a-lazyinitializationexception-no-hibernate/ vai lendo esse ai enquanto vejo outra possibilidade, esse post é muito parecido com seu problema.

B

Tive este mesmo problema.
no meu caso estava utilizando um <h:selectManyMenu com o value apontando para uma lista na qual eu queria inserir os itens selecionados
o que acontece e que na hora do jsf inserir os itens selecionados na lista ele não os converte como a lista é generia nada da errado ate o hibernate
tentar recuperala, neste momento em vez de recuperar uma List ele recupera uma List , sendo assim o objeto String não possui as
propriedades da suaclasse e a exception e lançada com a descrição dos atributos que não puderam ser encontrados em rumtime por reflexão ou metodos
getter e setter.

para resolver o problema vc deve recuperar os itens da List onde cada elemento corresponde ao valor retornado pelo metodo suaclasse.toString()
fazer uma parser para o tipo da sua ID e recuperar os dados no banco de dados.

qualquer duvida em relação a explicação poste junto a sua pergunta o codigo jsf responsavel por inserir os itens na List.

Criado 17 de dezembro de 2012
Ultima resposta 17 de abr. de 2014
Respostas 56
Participantes 6