Oi pessoal!
Fiz uma aleração na aplicação, eu tinha uma classe @Entity Usuario, agora eu tenho uma classe de interface Usuario e duas classes que serão persistidas, a Cliente e outra Funcionario.
Classe de interface Usuario:
public interface Usuario {
public String getNome();
public String getEmail();
public String getLogin();
public String getSenha();
public String getRole();
}
Classe Funcionario:
@Entity
public class Funcionario implements Usuario, Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
private String email;
private String login;
private String senha;
private String role;
public void setNome(String nome) {
this.nome = nome;
}
public void setEmail(String email) {
this.email = email;
}
public void setLogin(String login) {
this.login = login;
}
public void setSenha(String senha) {
this.senha = senha;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public String getLogin() {
return this.login;
}
public String getRole() {
return this.role;
}
public String getSenha() {
return this.senha;
}
public String getNome() {
return this.nome;
}
}
Ao chamar a aplicação no Browser, gerou as tabelas corretamente, criei um funcionario no banco com login e senha e ao digitar isto na aplicação me deu o erro:
exception
java.lang.IllegalArgumentException: Vraptor does not support this interface or abstract type: br.com.imobiliaria.bean.Usuario
br.com.caelum.vraptor.http.ognl.GenericNullHandler.instantiate(GenericNullHandler.java:65)
br.com.caelum.vraptor.http.ognl.ReflectionBasedNullHandler.nullPropertyValue(ReflectionBasedNullHandler.java:79)
ognl.ASTProperty.getValueBody(ASTProperty.java:118)
ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
ognl.SimpleNode.getValue(SimpleNode.java:236)
ognl.ASTChain.setValueBody(ASTChain.java:222)
ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
ognl.SimpleNode.setValue(SimpleNode.java:279)
ognl.Ognl.setValue(Ognl.java:737)
ognl.Ognl.setValue(Ognl.java:783)
br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.createViaOgnl(OgnlParametersProvider.java:132)
br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.createRoot(OgnlParametersProvider.java:108)
br.com.caelum.vraptor.http.ognl.OgnlParametersProvider.getParametersFor(OgnlParametersProvider.java:90)
br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.getParametersFor(ParametersInstantiatorInterceptor.java:83)
br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:68)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42)
br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:47)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.util.jpa.JPATransactionInterceptor.intercept(JPATransactionInterceptor.java:46)
br.com.caelum.vraptor.core.InstantiatedInterceptorHandler.execute(InstantiatedInterceptorHandler.java:47)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:46)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:80)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:65)
br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:70)
br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56)
br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
VRaptor não suporta Interface? Como poderia implementar essa tática de Interface para Cliente e Funcionário?
Acho que o problema não é o que o vraptor não trabalha com interfaces :). Provavelmente vc tem um metodo login(Usuario usuario), o lance aí é que o vraptor vai tentar instanciar esse usuario para popular com os valores vindos do formulario, e, como isso é uma interface, não vai rolar. Seu parametro deveria ser de um tipo concreto.
Pois é alots_ssa, ele está tentando instanciar o Usuario que agora é uma Interface, no AccesControllerInterceptor o restrictionResult pega o this.usuarioLogado.getPerfil(), este por sua vez instancia o Usuario, que possui o método getPerfil(), então precisaria que o usuarioLogado instanciasse o Cliente e o Funcionario, pegando seus respectivos getPerfil(), ou seja, tomar conta de duas classes ao invés de uma.
private Usuario usuarioLogado;
Já que Usuario é uma interface, como poderia instanciar o Cliente e o Funcionario através da classe usuarioLogado?
Como o vraptor consegue saber qual implementação usar? Não dá pra saber! Como vc faz pra diferenciar se é um Cliente ou um Funcionário na requisição?
de qqer forma, vc pode trocar essa sua interface por composição:
@Entity
public class Cliente {
//...
private Usuario usuario;
}
@Entity
public class Funcionario {
//...
private Usuario usuario;
}
e esse usuário tem aquelas propriedades que estão na interface… Se vc quiser que os dados fiquem nas tabelas Funcionario e Cliente, é só anotar o atributo usuario com @Embedded
Oi Lucas!!
Pelo que eu entendi, a classe Usuario ficaria assim:
@Embedded
public class Usuario {
public String getNome();
public String getEmail();
public String getLogin();
public String getSenha();
public String getRole();
}
E como eu anoto esse relacionamento dentro da classe Funcionario e Cliente?
@Entity
public class Funcionario {
//...Preciso de anotação aqui?
private Usuario usuario;
}
Pois é Garcia, a porta de entrada para a aplicação é o UsuarioLogado instanciar o Usuario, e este não pode ser interface e nem classe abstrata, que sinuca heim? =)
A dica do Lucas que eu não entendi ainda, em relação a classe Usuario dentro das classes Funcionario e Cliente.
[quote=Guevara]Pois é Garcia, a porta de entrada para a aplicação é o UsuarioLogado instanciar o Usuario, e este não pode ser interface e nem classe abstrata, que sinuca heim? =)
A dica do Lucas que eu não entendi ainda, em relação a classe Usuario dentro das classes Funcionario e Cliente.
Abraço!![/quote]
Quando ao fato de Usuario ser abstract ou interface isso é fato. O mais correto é class abstrata para usar a herança do hibernate. Porém acho que você que está fazendo errado. Porque você quer passar a classe abstrata e não a implementação? Você usa a mesma tela para cliente e a mesma para funcionário? Penso que embora possam todos herdar de usuário, na verdade são telas com cadastros e talvez até regras diferentes, então deveriam estar em telas diferentes.
A idéia é essa mesma, cadastro em telas diferentes, inclusive teria que fazer clienteLogado e funcionarioLogado e no AccesControllerInterceptor ficaria:
Cara, não vejo erro em nenhuma das situações. Em um sistema, um funcionário pode sim ser um usuário, bem como um cliente também pode sê-lo.
O problema é que Usuario acabaria sendo abstrato demais nessa situação, e ficaria impossível saber qual tipo de usuário (funcionário ou cliente) o framework deve injetar.
Então, deve-se usar as classes especializadas mesmo. Só que, para evitar a tão odiada (e mal usada) herança, o ideal é usar composição (um objeto é composto de outro).
Sei que isso essa discussão é velha, mas só quis dizer que não enxergo o problemas nas abordagens propostas. :thumbup:
eu discordo da estrategia de que um Funcionário pode ser um usuário…
Na verdade nem Cliente nem Funcionário, devem vim de uma Herença… eles são na verdade Pessoas…
Uma Pessoa não é um funcionario, ou uma pessoa é um cliente… Uma pessoa é uma pessoa e pronto…
…
Porem, quando uma Pessoa arruma um emprego, ela passa a ter informações relativa a este emprego, e portanto passam a ter um Funcionário, ou seja, a ter informações de funcionario… o mesmo com cliente, ate pq, um Funcionário também pode ser um cliente…
…
Esses casos são resolvidos fácilmente com composição.
Pessoa -- has --> FuncionarioInfo
|- -- has --> ClienteInfo
|- -- has --> UsuarioInfo
assim vc evita problemas com herença, e não vai se deparar com becos sem saída como o caso de um cadastro duplicado, só pq um Funcionário resolveu comprar algo na sua própria empresa … O.o …
Rapaz, eu desvirtuei todo o foco do tópico, sorry guys :oops: Guevara, não repara, a intenção é apenas te ajudar. Mas desvirtuando um pouco mais, concordo com tudo que o Laveri disse.
Penso que o ideal é fazer como o que o Lucas disse, criar três classe distintas (Usuario, Cliente e Funcionario), e fazer as telas distintas para cliente e funcionário. Caso um cliente ou um funcionario tenham acesso ao sistema através de login, aí você pode, por composição, incluir as informações de login/senha.
O que você acha, Guevara? Creio que assim você nem mesmo terá aqueles problemas iniciais do tópico.
Oi pessoal! =)
Obrigado pelas dicas, eu estava com a intenção de evitar herança, até pelo que eu já li a respeito, preferir composição à herança, mas não estou conseguindo colocar em código isso, os exemplos que eu pesquisei não batem com o que eu tenho para fazer essa composição.
Os atributos da classe Usuario serão os mesmos nas classes Cliente e Funcionario?
Fiz a classse Usuario:
@Entity
public class Usuario implements Serializable {
private static final long serialVersionUID = 1L;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="id_cliente")
private Cliente cliente;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="id_funcionario")
private Funcionario funcionario;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String login;
private String senha;
private String nome;
private String role;
//getters and setters
E a classe Funcionario:
@Entity
public class Funcionario implements Serializable {
private static final long serialVersionUID = 1L;
@Embedded
@OneToOne(mappedBy = "usuario")
private Usuario usuario;
public Usuario getUsuario() {
return usuario;
}
public void setUsuario(Usuario usuario) {
this.usuario = usuario;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id_funcionario")
private Long idFuncionario;
private String login;
private String senha;
private String nome;
private String role;
//getters and setters
Isso que eu fiz não funciona. =(
Os atributos login, nome, senha e role ficam na classe Usuario ou nas classes Cliente e Funcionario? Não sei em que lado do relacionamento ficam os atributos, isso não ficou claro pra mim.
Outro problema, o método getPerfil() têm que estar na classe Usuario, senão o usuarioLogado não consegue obter o perfil.
Abraço!!
Guevara… se quiser colocar a ligação com Usuario em mais de uma classe, então cria uma INterface “HasUsuario” nesta interface só terá um método “getUsuario()” (no máximo 2, com o setUsuario, mas só coloque o segundo quando precisar em algum método)…
algo como:
public class Funcionario implements HasUsuario {... }
public class Cliente implements HasUsuario {... }
public class Etcs implements HasUsuario {... }
Fora isso onde vc precisar de um usuário vc coloca
public void seuMetodo(HasUsuario hasUsuario) {
seuMetodo(hasUsuario == null ? null : hasUsuario.getUsuario());
}
public void seuMetodo(Usuario usuario) {
//... aki vc coloca sua lógica
}
pronto agora vc consegue usar polimorfismo…
Ps.: ahh claro, faça o que o lucas falou, mover as informações para dentro de usuário