Na empresa na qual trabalho esta sendo criado um pequeno framework de seguranças e auditoria. sendo que este framework irá utilizar hibernate. O grande problema é o seguinte criei um HibernateUtils para criar a SessionFactory e leio o mapeamento das classes pelo hibernate.cfg.xml e o HibernateGenerics que serve de classe base para o DAO, no framework a parte de usuario, permissao, fica dentro do framework. Gostaria de saber como reutilizar isso em outros projetos. Por exemplo ao importar a biblioteca utilizar para que ao criar novos POJOS ao criar os DAO do POJO ele Herdar de HibernateGenerics e saberem fazer a persistencia, se eu deixar o mapeamento em outro local posso mapear classes de dois projetos diferentes nele. Existe uma solução melhor para resolver esse problema, tendo em vista que não posso deixar nas aplicações o código fonte de entidades como usuario, permissão, etc…, por isso estou usando esse framework, e essa parte das consultas com persistencia é um requisito que não fiquem expostas, pois algumas aplicações criadas o código fonte será fornecido.
A forma como estou pensando em criar o arquivo de mapeamento fora dos projeto e quando criar a session factory ler os mapeamentos de lá funcionará?
Alguem já utilizou dessa forma, caso eu não tenha sido claro me avisem que detalho mais o problema.
Hibernate Annotation dentro de "framework corporativo"
14 Respostas
primeiro lugar alguns conselhos....
HibernateBlaBla<T> é furada... na certa... eu falo por experiencia, já usei essa abordagem, e ela é o mesmo que andar para traz....
Encapsular uma Session, dentro de um DAO e tipar ele, é voltar no tempom uma session é totalmente receptiva a qualquer tipo de entidade, então não há sentido em criar um adaptador que restringa o acesso ....
Dao foi um padrao criado, para a epoca de java.sql.* ...
Vc pode criar um Repositorio que aceito qualquer coisa, no lugar de criar dezenas de Daos, enfim, posso descutir mais sobre isso se tiver interesse, eu uso essa abordagem de um único Repositorio.... (antes que fique curioso de saber como abordo as queries de varios tipo de entidades, eu não coloco elas dentro do repositorio, tenho outra solução, se tiver interesse nois conversamos).
.........
Sobre o seu mapeamento, vc pode mapear tudo com annotation, normalmente, e usar o ORM.XML para trocar o mapeamento dessas classes especificas em cada projeto, eu uso isso, nos meus... no meu pacote base eu tenho as classes Acesso, Papel, Funcionalidades .... mas em cada projeto ela pode estar diferente, ou em um banco diferente, ou qualquer coisa do genero.... essas classes são todas anotadas, quando preciso troco algo no ORM.XML ... que deve ficar dentro de meta inf.... segue um exemplo de ORM
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">
<entity class="br.com.tomazlavieri.acesso.model.Acesso"></entity>
<entity class="br.com.tomazlavieri.acesso.model.Papel"></entity>
<entity class="br.com.tomazlavieri.acesso.model.Funcionalidade"></entity>
</entity-mappings>
ai eu só listo elas, para o Hibernate enchergar elas, pois elas estão dentro de um .jar .... mas poderia alterar propriedades entre outras coisas, como no exemplo abaixo
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0" xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">
<entity class="br.com.tomazlavieri.acesso.model.Acesso" access="PROPERTY">
<table catalog="acessodb" schema="dbo"/>
<attributes>
<many-to-many name="papeis">
<join-table catalog="acessodb" schema="dbo"/>
</many-to-many>
<many-to-many name="permitidas">
<join-table name="Acesso_Permitido" catalog="acessodb" schema="dbo"/>
</many-to-many>
<many-to-many name="negadas">
<join-table name="Acesso_Negado" catalog="acessodb" schema="dbo"/>
</many-to-many>
</attributes>
</entity>
<entity class="br.com.tomazlavieri.acesso.model.Papel" access="PROPERTY">
<table catalog="acessodb" schema="dbo"/>
<attributes>
<many-to-many name="permitidas">
<join-table name="Papel_Permitido" catalog="acessodb" schema="dbo">
</join-table>
</many-to-many>
<many-to-many name="negadas">
<join-table name="Papel_Negado" catalog="acessodb" schema="dbo">
</join-table>
</many-to-many>
</attributes>
</entity>
<entity class="br.com.tomazlavieri.acesso.model.Funcionalidade" access="PROPERTY">
<table catalog="acessodb" schema="dbo"/>
</entity>
</entity-mappings>
Lavieri como faz bastante tempo que eu não programava em Java por volta de 2 anos, estava utilizando a abordagem que eu conhecia, mas achei bastante interessante essa abordagem por repositório, se houver algum material que possa me passar ou algum exemplo ficarei grato, outra coisa para evr se eu entendi o ORM.XML fica dentro do meu .jar do framework, minha pergunta agora é o seguinte no seus projeto se tu criar uma classe Pessoa como o teu pacote base vai enxergar o mapeamento, o ORM.XML será um só incluindo os mapeamento do pacote base mais a classe Pessoa ou serão dois ORM.XML diferentes?
o ORM.XML não fica no base… ele fica no projeto onde vc vai incluir…
nele vc adiciona as linhas para o seu pacote… normalmente só vai ter ela… pq as classes que não estão em pacotes .jar, podem ser enchergadas sem o “orm.xml”
ele fica dentro da pasta src/META-INF/
juntamento com o persistence.xml
…
esse ORM.XML sobrescreve as anotações que estão no objeto original dentro do .jar …
…
VC adiciona o seu base.jar … e coloca o “orm.xml” no pacote do seu novo projeto… e configura as classes que estão dentro do .jar da melhor forma dentro do projeto novo
…
Responde sobre o Repository em outro post, pra não ficar muito extenso esse aqui
Repository é um lugar onde vc coloca suas entidades, e la dentro elas ficam persistidas....
Fazer um adaptador para uma Session é bom, pois caso o mundo caia, a versão troque, as coisas mudem, seu projeto vai estar protegido contra os refectorings e e contra os deprecated do Hibernate....
a ideia é, um repository é um Lugar onde vc pode incluir suas entidades, remover entidades, atualizar entidades, pesquisar entidades, listar, iniciar tranzações e finalizar, dar rollback etc, o basico...
O Repository aceita qualquer entidade, e não só uma tipada....
ou seja.... nada de 30 DAO para 30 entidades.... afinal, ADD, REMOVE, UPDATE são a mesma operação quando se trata de uma session, e podem todas serem feita no mesmo lugar no repositorio....
Um problema fica, onde Colocar as consultas ? de cada tipo de Entidades ? se não em DAO ? um para cada entidades ? a solução vem de separar o antigo DAO em duas partes...
1° o lugar onde se faz operaçoes de modificação, essa parte é comum a todas as entidades, e fica dentro do repositorio.
2° o lugar onde guarda as pesquisar, ou seja, onde tem os métodos para cada tipo de pesquisa... esse lugar é transportado para fora do DAO (que agora virou um único repositorio), e vai para dentro de um objeto Query, onde tem a pesquisa.
assim vc vai ter abordagens como
Curso curso = queries.forCurso().byName("computacao").queryOn(repository);
Matricula matricula = new Matricula(aluno,curso);
repository.addAll(pessoa,aluno,matricula);
o objeto queries, é uma Fachada, ele centraliza chamadas para as queries separadas, ou seja, ele tem métodos como:
forCurso()
forAluno()
forPessoa()
forMatricula()
forEtc()
cada um desse métodos retorna um objeto chamado QueryX, onde o X é o que vem depois do for, por exemplo...
CursoQuery forCurso() {
return CursoQuery.getInstance();
}
AlunoQuery forCurso() {
return AlunoQuery.getInstance();
}
esses objetos Query é onde fica as consultas personalizadas .... para cada tipo de entidade ... assim vc separa bem os códigos, mas tem um ponto de acesso comum, o objeto queries....
para Exemplificar vou mostrar como fica essa chamada => "Curso curso = queries.forCurso().byName("computacao").queryOn(repository);"
bom, ate forCurso, já foi visto, isso vai retorar um CursoQuery ....
public class CursoQuery {
//... métdo abaixo é um singleton, se não souber como fazer fala, q posso mostra o código de um
public static CursoQuery getInstance() { ... }
public Query<Curso> byName(String name) {
DetachedCriteria dc = DetachedCriteria.forClass(Curso.class).add(Restrictions.eq("name",name));
return new HibenateQueryUnique<Curso>(dc);
}
}
O Query<T> é uma interface, que o método queryOn(repository) que é em que repository a query deve ser executada...
O HibenateQueryUnique é um utulitario para hibernate que implementa essa interface para datechades criteria...
public class HibernateQueryUnique<E> implements Query<E> {
public E queryOn(Repository repository) {
return ((HibernateRepository) repository).uniqueResult(dc);
}
}
e o repository.uniqueResult(dc) executa a consulta assim...
public <T> T uniqueResult(DetachedCriteria dc) throws RepositoryException {
return (T)dc.getExecutableCriteria(getSession()).uniqueResullt();
}
bom, pode parecer complicado, mas na pratica não é.... o fato é que...
...................
Repository é uma interface e vc só escreve ela 1 vez
HibernateRepository é uma implementação da interface vc só escreve ela uma vez, e nunca mais
Query<T> é uma interface vc só escreve ela uma vez, e nunca mais...
HibernateQueryUnique é uma impelmentação para DatechedCriteria, chamando o método Unique, vc só escreve ele uma vez... assim como tem também o HibernateQueryList, entre outros q vcpossa querer criar/usar ....
Queries é uma fachada.... vc escreve um por projeto, mas ele quase não tem código, ele só tem método forEntidadeX() e retorna o EntidadeXQuery.
EntidadeXQuery, esse sim é p único objeto que vc escreve 1 por classe.... nele se guarda as queries, que vc precisa no seu projeto para aquela entidade...
e só lembrando... não é necessário ter 1 EntidadeXQuery por entidade... ele só é necessário quando vc precisa fazer queries mais complexas, pois as queries comuns
seu repositorio pode prever e implementar... por exemplo
repository.list(Curso.class); (não há necessidade de fazer isso pelo queries)
repository.get(Curso.class,id);
essas duas pesquisas são iguais para todos as entidades .... vc só poem no XQuery consultas personalizadas...
.............
assim vc tem códigos mais ligveis, mais fluentes
um exemplo onde uso essa abordagem no meu código
Usuario valido = queries.forUsuario().byLoginSenha(login, senha).queryOn(repository);
if (valido != null) {
this.usuario = valido;
loggedIn = true;
super.login(this.usuario.getRole());
repository.add(new RegistraLogin(usuario)); //registra no banco a logada.
}
fica bem melhor do que se fosse com DAO, onde eu teria que instanciar um Dao de usuarios e ai usar o seu método de login, e ainda teria q saber onde se econtra o dao... alem disso teria q instancia outro dao para a entidade RegistrarLogin, pois também dou um persist nela....
com repository o lugar é unico, e as queries estão sempre no objeto queries, e assim fica facil de fazer...
segue ai minha interface de repository
Entendi por parte da questão do repositorio estou começando a implementar aqui fazendo os testes fica bem mais flexivel algumas perguntas agora:
1- Além do hibernate anotatiosn utiliza-se de outro framework como spring no base.jar, pergunto pois meu projeto a principio poderam ser desktop e/ou web.
2- As bibliotecas do hibernate ficam no projeto ou no base?Outra coisa como uso hibernate annotation ele não reconheceu persistence.xml, tive de usar hibernate.cfg.xml, estou fazendo algo de errado?
3- A interface Query,OrderList,QueryList foi criada por você ?
Essas são as dúvidas que surgiram se puder dar uma luz Lavieri fico grato. Sobre essa parte de repository, sabe me informar se alguem já criou algum tutorial sobre isso pesquisei no google e não achei muita coisa
Entendi por parte da questão do repositorio estou começando a implementar aqui fazendo os testes fica bem mais flexivel algumas perguntas agora:1- Além do hibernate anotatiosn utiliza-se de outro framework como spring no base.jar, pergunto pois meu projeto a principio poderam ser desktop e/ou web.
2- As bibliotecas do hibernate ficam no projeto ou no base?Outra coisa como uso hibernate annotation ele não reconheceu persistence.xml, tive de usar hibernate.cfg.xml, estou fazendo algo de errado?
3- A interface Query,OrderList,QueryList foi criada por você ?Essas são as dúvidas que surgiram se puder dar uma luz Lavieri fico grato. Sobre essa parte de repository, sabe me informar se alguem já criou algum tutorial sobre isso pesquisei no google e não achei muita coisa
R: 3) foi eu mesmo quem criou elas…
Query http://pastebin.com/TFtfDqT0
QuerList http://pastebin.com/wqUXKawr
OrderList http://pastebin.com/T4mBEQPK
R: 2) No meu base, só tem meus arquivos, a dependencia ficam em uma pasta lib… cada projeto separado copio as dependencias… o persistence.xml tem que ficar dentro da pasta META-INF do SRC … do projeto corrente, não pode ficar denro do JAR
R: 1) eu não uso nada além do necessário, a parte do repositorio não tem nada de web nele
Vamos ver se estou seguindo o caminho certo, criei as interface s de repository, etc..
vamos para as classes concretas:
Criei uma
public class Dao implements Repository {
private EntityManager manager = null;
public Dao() {
this.manager = HibernateUtils.getEntityManager();
}
public void close() throws RepositoryException {
this.manager.close();
}
public boolean isOpen() throws RepositoryException {
return this.manager.isOpen();
}
public void beginRecording() throws RepositoryException {
this.manager.getTransaction().begin();
}
public void commitRecord() throws RepositoryException {
this.manager.getTransaction().commit();
}
public void rollbackRecord() throws RepositoryException {
this.manager.getTransaction().rollback();
}
public void add(Object entity) throws RepositoryException {
try
{
this.beginRecording();
this.manager.persist(entity);
this.commitRecord();
}
catch (Exception ex) {
this.rollbackRecord();
throw new RepositoryException(ex);
} finally {
if (this.manager != null) {
this.manager.close();
}
}
}
public void addAll(Collection<?> entitys) throws RepositoryException {
try
{
this.beginRecording();
for(Object o:entitys)
{
this.manager.persist(o);
}
this.commitRecord();
}
catch (Exception ex) {
this.rollbackRecord();
throw new RepositoryException(ex);
} finally {
if (this.manager != null) {
this.manager.close();
}
}
}
public void addAll(Object... entitys) throws RepositoryException {
try
{
this.beginRecording();
for(Object o:entitys)
{
this.manager.persist(o);
}
this.commitRecord();
}
catch (Exception ex) {
this.rollbackRecord();
throw new RepositoryException(ex);
} finally {
if (this.manager != null) {
this.manager.close();
}
}
}
public void remove(Object entity) throws RepositoryException {
try
{
this.beginRecording();
this.manager.remove(entity);
this.commitRecord();
}
catch (Exception ex) {
this.rollbackRecord();
throw new RepositoryException(ex);
} finally {
if (this.manager != null) {
this.manager.close();
}
}
}
public void removeAll(Collection<?> entitys) throws RepositoryException {
try
{
this.beginRecording();
for(Object o:entitys)
{
this.manager.remove(o);
}
this.commitRecord();
}
catch (Exception ex) {
this.rollbackRecord();
throw new RepositoryException(ex);
} finally {
if (this.manager != null) {
this.manager.close();
}
}
}
.....
criei um HibernateUtils para me retornar o entity manager
public class HibernateUtils {
private static EntityManagerFactory emf = null;
public static EntityManager getEntityManager() {
if(emf==null)
{
emf = Persistence.createEntityManagerFactory("PU");
}
return emf.createEntityManager();
}
}
a parte das queries que falous nos post anteriores ententi que na implementação do do repositorio que no caso chamei de Dao, irei passar alguem que implementa a interface Query
quase ^^
é por ai… mas vamos a alguns pontos…
public void add(Object entity) throws RepositoryException {
try
{
this.beginRecording();
this.manager.persist(entity);
this.commitRecord();
}
catch (Exception ex) {
this.rollbackRecord();
throw new RepositoryException(ex);
} finally {
if (this.manager != null) {
this.manager.close();
}
}
}
nesse trecho há varias suposições e muitas deleas podem não ser verdade…
1°) que um .add é dado sem um escopo de tranzação aberto
2°) que sempre que um commit falhar vc deve dar rollback
3°) que não existira operação após um .add, pois vc da um close no repositorio…
essas suposições são sempre verdade ? se não forem é bom olhar com cautela… abaixo vem a minha implementação… é com session, mas segue o mesmo reciocinio
Segue parte da minha implementação, tudo que é preciso pra um add esta ai…
dessa forma eu posso adicionar 20 entidades, dentro de uma única tranzação…
editado para deichar o post mais clean, colocando o código no paste.bin
outra dica… do seu addAll(Object … entitys)
para o seu addAll(Collection<?> entitys)
não muda nada em relação a lógica então use a mesma lógica… duplicar a lógica é problema, pois escrever 2 vezes, da chance pra acontecer bug 2 vezes…
vc pode fazer o seguinte
addAll(Object ... entitys) {
addAll(Arrays.asList(entitys));
}
Lavieri tua ajuda foi minha salvação, como fazia uns dois anos que eu não programava em Java percebi que estava bastante desatualizado, valews pelas dicas cara estão sendo muito uteis, consegui assimiliar muita coisa do que me escreveu, qualquer dúvida que tenho ainda continuo postando aqui, ou crio um novo tópico, mas acho melhor colocar aqui para seguir a lógica de raciocinio.
bom ai é uma escolha que vc tem q fazer, se achar inerente a este assunto, pode colocar aqui…
caso seja sobre outras coisas pode abrir outro tópico…
se postar aqui, vai acabar q só eu vou te ajudar… mas se abrir novo topico mais gente vai ler… é mais dificil alguem entrar pra ler um topico exentso como esse
…
no mais bom saber que esta ajudando… ^^ … não muito desatualizado não… apesar de DAO ser da epoca do java.sql.* … muito gente usa, e inclusive muita gente pega uma solução com uma session ou um entitymanager e restringe seu acesso tipando ele…
…
fazer diferente muitas vezes é um desafio que vale a pena…