Category Archives: Hibernate

JPA/Hibernate Static Metamodel Attributes não populados / nulos — Gerando NullPointerException

E ai galera, beleza?

Hoje tive um problema tentando utilizar os atributos metamodel estáticos do JPA/Hibernate,
sempre quando eu ia utilizá-los, eles estavam nulos… depois de um tempo quebrando a cabeça consegui achar o motivo!

Vamos exemplificar o cenário:

Entidade:

package com.mydomain.model.user;

public class User {

/** Número de identificação */
@Id
private Long id;

/** Nome de autenticação */
private String username;

//getters e setters
}

Metamodel:

package com.mydomain.metamodels;

import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.StaticMetamodel;

@StaticMetamodel(User.class)
public class User_ {
public static volatile SingularAttribute<User, String> username;
}

Uso do metamodel no predicado (predicate):


cb.equal(root.get(User_.username), “usuario_teste”);

Toda vez que eu tentava dar get(…) eu estava tomando nullpointerexception,
e a solução que encontrei foi colocar a classe User.class e a User_.class no mesmo pacote…
não sei o real motivo para precisarem estar, porém só assim funcionou pra mim..

Pesquisando descobri também que em futuros releases talvez essas classes possam ficar em pacotes diferentes,
segue algumas regras descritas na especificação do JPA 2:

  • Classes Metamodel devem estar no mesmo pacote das classes de entidade que elas descrevem;
  • Elas devem ter o mesmo nome das classes de entidade que elas descrevem, seguido por um traço-baixo (“_”, underline, underscore…).
    Exemplo: Produto.class é a classe de entidade e o Produto_.class é a classe metamodel.
  • Se uma entidade herdar de outra entidade ou de uma superclasse mapeada (mapped superclass) deve herdar da classe metamodel que descreve sua superclasse.
    Exemplo: Se ProdutoEspecial.class estende Product.class, que estende ObjetoPersistente.class, então ProdutoEspecial_.class deve estender Produto_.class, que deve estender ObjetoPersistente_.class.

É isso ai pessoal espero ter ajudado!
valeu!!!

Fonte: stackoverflow.com – debbie/Vítor E. Silva Souza

Anúncios

Como persistir LocalDate e LocalDateTime do Java 8 com JPA

E ai galera beleza? faz muito tempo que eu não postava nada novo, então bora com “novidade” do java 8 + JPA 😀

O Java 8 trouxe muitas grandes funcionalidades e uma das mais importantes e uma das antecipadas foi a nova API de data e hora. Haviam muitos problemas com a antiga API e não vou entrar em detalhes do porque nós precisamos de uma nova. Tenho certeza que você teve que lutar com ela com frequencia.

Todos esses problemas se foram com Java 8 \o/. A nova API de data e hora é bem desenhada, fácil de usar e (finalmente) imutável. O único problema que permanece é, que você não pode usava com JPA.

Bem, isso não totalmente verdade. Você pode usa-la, porém o JPA irá mapeá-la para BLOB ao invés de DATE ou TIMESTAMP. Que significa que a base de dados não está ciente do objeto de data e não pode aplicar nenhuma otimização para isso. E não é desse jeito que deveríamos ou gostaríamos de fazê-lo.

Porque o JPA não suporta LocalDate e LocalDateTime?

A resposta é simples, o JPA 2.1 foi liberado antes do Java 8 e a API de data e hora simplesmente não existia naquela época. Portanto a anotação @Temporal pode apenas ser aplicada a atributos do tipo java.util.Date e java.util.Calendar.

Se você deseja armazenar um atributo LocalDate em uma coluna Date ou uma LocalDateTime em uma coluna TIMESTAMP, você mesmo precisa definir o mapeamento para java.sql.Date ou java.sql.Timestamp. Graças ao conversor de atributo, uma das diversas novas funcionalidades do JPA 2.1, isso pode ser alcançado com apenas algumas linhas de código.

Nos exemplos abaixo, eu vou mostrar pra vocês como criar um conversor de atributos para LocalDate e LocalDateTime. Se você quer aprender mais sobre conversor de atributo, dê uma olhada aqui (inglês).

O exemplo

Antes de nós criar os conversores de atributo, vamos dar uma olhada na entidade de exemplo para esse post:

@Entity
public class MyEntity {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = “id”, updatable = false, nullable = false)
private Long id;

@Column
private LocalDate date;

@Column
private LocalDateTime dateTime;

}

O conversor de atributo faz parte da especificação do JPA 2.1 e pode portanto ser usado com qualquer implementação de JPA 2.1, ex.: Hibernate ou EclipseLink. Eu usei Wildfly 8.2 com Hibernate 4.3 para os seguintes exemplos.

Convertendo LocalDate

Como você pode ver no seguinte pedaço de código, não é necessário muita coisa para criar um conversor de atributo para LocalDate.

@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {

@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}

@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}

Você precisa implementar a interface AttributeConverter<LocalDate, Date> e seus 2 métodos convertToDatabaseColumn e convertToEntityAttribute. Como você pode ver nos nomes dos métodos, um deles define a conversão do tipo do atributo da entidade (LocalDate) para o tipo de coluna da base de dados (Date) e o outro é a conversão inversa. A conversão em si é simples porque java.sql.Date ja nos provê o método para fazer a conversão “de” e “para” um LocalDate.

Adicionalmente o conversor de atributo precisa ser anotado com a anotação @Converter. Devido a propriedade opcional autoApply=true, o conversor será aplicado a todos os atributos do tipo LocalDate. Dê uma olhada aqui (inglês), se você quer definir o uso de cada conversor para cada atributo individualmente.

A conversão do atributo é transparente para o desenvolvedor e o atributo LocalDate pode ser usado como qualquer outro atributo da entidade. Você pode usa-lo como parâmetro de query por exemplo.

LocalDate date = LocalDate.of(2015, 8, 11);
TypedQuery<MyEntity> query = this.em.createQuery(“SELECT e FROM MyEntity e WHERE date BETWEEN :start AND :end”, MyEntity.class);
query.setParameter(“start”, date.minusDays(2));
query.setParameter(“end”, date.plusDays(7));
MyEntity e = query.getSingleResult();

Convertendo LocalDateTime

O conversor de atributo para LocalDateTime é basicamente o mesmo. Você precisa implementar a interface attributeConverter<LocalDateTime, Timestamp> e o conversor precisa ser anotado com a anotação @Converter. Assim como o LocalDateConverter, a conversão entre LocalDateTime e um java.sql.Timestamp é feita através dos métodos de conversão do Timestamp.

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {

@Override
public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
}

@Override
public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDate());
}
}

Conclusão

O JPA 2.1 foi liberado antes do Java 8 e portanto não suporta a nova API de data e hora. Se você quer usar as novas classes (do jeito certo), você mesmo precisa definir a conversão para java,sql.Date e java.sql.Timestamp. Isso pode ser feito facilmente implementando a interface AttributeConverter<EntityType, DatabaseType> e anotando a classe com a anotação @Converter(autoApply=true). Setando autoApply=true, a conversão será aplicada a todos os atributos do EntityType e nenhuma alteração na entidade é necessária.

Até onde eu sei, a próxima versão do JPA suportará a nova API de data e hora e as diferentes implementações provavelmente irão suporta-la ainda mais cedo. O Hibernate 5 por exemplo irá suporta-la como uma funcionalidade proprietária.

É isso ai galera, espero tê-los ajudado 😀

Fonte: thoughts-on-java.org – Thorben Janssen

JPA2/Hibernate – Auto-incremento em colunas non-id (sem anotação @Id)

E ai galera beleza? hoje tive um problema ao tentar implementar:

@SequenceGenerator(name="MINHA_SEQUENCE", sequenceName="MINHA_SEQUENCE", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="MINHA_SEQUENCE")

em uma coluna que não tinha @Id… simplesmente não estava criando a sequence, consequentemente, não gerava o valor automatico…

achei a seguinte solução: (não utiliza as anotações @SequenceGenerator e @GeneratedValue)

@Column(columnDefinition="serial")
@Generated(GenerationTime.INSERT)

testei no postgresql e funcionou perfeitamente!

Espero que ajude 😀 abraços !

Fonte: Sergey Vedernikov – Stackoverflow / axtavt – Stackoverflow

JBoss – Criando/Configurando um Datasource

E ai galera beleza, segue um tutorial de como criar um Datasource utilizando MySQL (ou qualquer outro Banco de Dados) no JBoss…

1. No arquivo JBOSS_HOME\standalone\configuration\standalone.xml :
(procure as linhas abaixo…)

<subsystem xmlns=”urn:jboss:domain:datasources:1.0″>
<datasources>
<datasource jndi-name=”java:jboss/datasources/ExampleDS” pool-name=”ExampleDS” enabled=”true” use-java-context=”true”>
<connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1</connection-url>
<driver>h2</driver>
<security>
<user-name>sa</user-name>
<password>sa</password>
</security>
</datasource>
<drivers>
<driver name=”h2″ module=”com.h2database.h2″>
<xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
</driver>
</drivers>
</datasources>
</subsystem>

Adicione as seguintes linhas após a tag  </datasource>:
<datasource jta=”true” jndi-name=”java:jboss/datasources/seuDataSourceDS” pool-name=”seudatasource” enabled=”true” use-java-context=”true” use-ccm=”true”>
<connection-url>jdbc:mysql://localhost:3306/seubancodedados</connection-url>
<driver>mysql</driver>
<security>
<user-name>root</user-name>
<password>suasenha</password>
</security>
</datasource>

Adicione as seguintes linhas após a tag  </driver>:
<driver name=”mysql” module=”com.mysql”>
<xa-datasource-class>com.mysql.jdbc.Driver</xa-datasource-class>
</driver>

2. Adicione o seu arquivo jar do driver do banco (mysql-connector-java-X.X.X-bin.jar) na pasta JBOSS_HOME\modules\com\mysql\main (caso o diretorio mysql\main não exista crie-o).

3. Nesta mesma pasta crie o arquivo module.xml com o seguinte conteudo: (cuidado para não deixar nenhum espaço em branco no começo do conteudo do arquivo, pode dar problema!)

<?xml version="1.0" encoding="UTF-8"?>

<module xmlns="urn:jboss:module:1.0" name="com.mysql">
  <resources>
    <resource-root path="mysql-connector-java-X.X.X-bin.jar"/>
  </resources>
  <dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
  </dependencies>
</module>

Se estiver utilizando JPA/Hibernate adicione a seguinte linha no seu persistence.xml:
<jta-data-source>java:jboss/datasources/seuDataSourceDS</jta-data-source>

Bom espero que ajude, achei essa configuração indo atrás de um erro que tomei:

New missing/unsatisfied dependencies: service jboss.naming.context.java.jboss.datasources.XXXXX (missing) dependents: [service jboss.persistenceunit."..."]

Acredito que é a mesma regra para os outros bandos de dados (mudando as devidas informações)… See ya 😀

Fonte: StackOverflow – Piotr Kochański / sven / appa

TransientObjectException, LazyInitializationException e outras famosas do Hibernate

Para quem desenvolve com Hibernate, sem dúvida as exceptions que aparecem mais são a TransientObjectException (TOE), LazyInitializationException (LIE) e a PersistentObjectException (POE). Semana passada tive o prazer de ministrar um treinamento de EJB3 e JSF para o pessoal da Petrobras de 5 cidades diferentes e durante o curso várias TOEs, POEs e LIEs apareceram. Vamos ver quando cada uma ocorre.

Estou usando aqui a API do Java Persistence, mas a relação é direta com o Hibernate, já que este é o meu provider. Considere duas entidades, Autor e Livro, cada uma com atributos triviais, um id que é @GeneratedValue e uma relação @ManyToMany entre elas, sendo Livro que possui o lado mappedBy. Vamos ao código:

Autor a = new Autor();
Livro l = new Livro();
a.setLivros(Collections.singleton(l));
manager.persist(a);

Resultado:

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: br.com.caelum.hibernate.testes.Livro

Essa exception não ocorreria se você tivesse chamado manager.persist(l); dentro dessa mesma transação, ou utilizasse cascade=CascadeType.PERSIST no relacionamento. Um objeto transiente, ao ser persistido, não pode se referenciar a outros objetos transientes, a não ser que haja cascade!

Agora considere:

Autor a = new Autor();
a.setId(1L);
a.setNome("paulo");
    
manager.persist(a);

Resultado:

org.hibernate.PersistentObjectException: detached entity passed to persist: br.com.caelum.hibernate.testes.Autor

O id de Autor está anotado com @GeneratedValue, quando ele percebe que há um id setado ele imagina que provavelmente esse objeto já deve existir no banco de dados (repare que ele não faz select, se você colocar um id que não existe, a mesma exception ocorrerá). persist não aceita objetos detached, apenas transient e managed. Essa exception não ocorreria se seu id não fosse @GeneratedValue, ou se você tivesse puxado esse Autor através do manager.find, por exemplo.

Vamos passar para o método merge. Porque o utilizamos tanto? Pois na web, quando recebemos os parâmetros e populamos nosso Entity para atualizá-lo, ele está detached: não foi pego através do EntityManager/Session, porém possui um id setado (o que anteriormente gerou a PersistentObjectException). O merge tem um detalhe importantíssimo: ele não vai passar o estado daquela entidade para managed (como faz o saveOrUpdate do Hibernate), e sim devolver uma versão da mesma entidade que seja managed (como fazia o velho saveOrUpdateCopy), em outras palavras, futuras mudanças na entidade passada não surtirão efeito. A outra grande diferença é que agora podemos passar como argumento um objeto transiente que já possua um id setado:

Autor a = new Autor();
a.setId(1L);
a.setNome("livro1"); 
manager.merge(a);
a.setNome("livro2");

O código irá atualizar o nome do Livro de id 1 para livro1. Repare que a mudança para livro2 não surtirá efeito, já que o merge não faz attach do objeto passado como argumento, então nesse caso ele continua detached. Uma opção seria você pegar o retorno do método merge, que é o mesmo Autor, porém agora managed. A documentação do hibernate sobre o merge parece ser melhor que a especificação.

Aqui temos de ter muito cuidado, como não puxamos esse Autor pelo entityManager, caso ele possua alguns livros no seu relacionamento, nesse merge perderíamos todas essas informações!

Parece fácil evitar todas essas exceptions, então porque eu disse que ocorreram tanto no curso? Bem, estávamos usando a JPA de dentro de um container, não standalone. Considere então um session bean de granularidade fina que esteja agindo apenas como um dao (esse não é o ideal, mas fica para os testes):

@Remote
interface SessionBeanRemote {
  void persiste(Autor a);
  void persiste(Livro l);
  Livro buscaLivroPorNome(String nome);
}

E considere o cliente:

Livro l = new Livro();
sessionBeanRemoto.persiste(l);
Autor a = new Autor();
a.setLivros(Collections.singleton(l));
manager.persiste(a);

Repare como esse código é muito parecido com o primeiro desse post, porém já persistindo o Livro anteriormente, para evitar a TransientObjectException. Mas adivinhe, aqui é lançada uma TOE! Isso ocorre porque, apesar do Livro ter sido persistido, no cliente remoto ele estará transiente, pois sua chave primária não foi populada, já que o objeto foi serializado e só no servidor se encontra uma versão desse Livro com sua respectiva chave! Se fosse no EJB 2.x, onde o Entity bean também é um componente, isso não ocorreria. Mas aqui, fora do container, o Entity bean age realmente como um valeu object: não há ligação dele com o servidor.

Para resolver isso temos alguns idiomismos, mudaríamos nosso bean remoto para:

@Remote
interface SessionBeanRemote {
  Autor persiste(Autor a);
  Livro persiste(Livro l);
  Livro buscaLivroPorNome(String nome);
}

Um tanto estranho, e na nossa implementação devolveríamos o próprio argumento:

@Stateless
class SessionBean implements SessionBeanRemote {
  @PersistentContext
  private EntityManager manager;
  public Livro persiste(Livro l) {
    manager.persist(l);
    return l;
  }
  // outros metodos
}

Dessa maneira passaríamos de volta ao cliente uma versão detached do novo livro: agora com ID! Nosso cliente ficaria:

Livro l = new Livro();
l = sessionBeanRemoto.persiste(l); // agora pegamos o retorno!
Autor a = new Autor();
a.setLivros(Collections.singleton(l));
manager.persiste(a);

Existem outras alternativas, como retornar apenas a chave primária, utilizar session beans com maior granularidade, etc.

E a LazyInitializationException que mencionei? Usando hibernate ou JPA standalone estamos cansados de saber como evitá-la: basta manter a sessão aberta durante a renderização na camada de visualização. Mas com EJB a história é outra, sendo muito mais sutil: chame o método buscaPorNome, ele vai retornar ao cliente um Livro detached. Adivinhe o que acontece ao invocar o getAutores() no cliente?

Fonte: Paulo Silveira – Caelum

Ei! Como é o seu DAO? Ele é tão abstraído quanto o meu?

Essa é uma pergunta comum entre os desenvolvedores. Alguns acham que há uma fórmula única, que DAO é um pattern fechado e que possui seu diagrama de classes bem definido. Eu discordo.

Na minha humilde opinião, DAO é uma maneira de você encapsular o seu acesso a dados. Não importa se é através de uma factory de objetos que recebem uma Session do hibernate por injeção de dependências, ou se é um montão de métodos estáticos cheio de SQL dentro deles (argh!). Obviamente a última opção envolve diversos outros antipatterns (como singleton e métodos estáticos, que já criticamos anteriormente), porém ela consegue isolar seu acesso a dados, cumprindo o papel do DAO e de alguma maneira organizando sua camada.

Lendo a definição de Data Access Object no site da Sun, podemos chegar a um molde comum, mas nada impede que possamos incrementa-lo e modifica-lo de acordo com nossas necessidades. Por exemplo, com o Java 5, podemos tirar proveito dos generics. Na Caelum costumamos usar uma interface para os nossos DAOs parecida com a seguinte:

interface Dao<T> {
  T search(Serializable id);
  void persist(T t);
  void remove(T t);
  // ...
}

A nossa implementação de DAO genérico para hibernate fica parecida com:

class GenericHibernateDao<T> implements Dao<T> {
  private Session session;
  private Class persistentClass;
  public GenericHibernateDao(Session session, Class persistentClass) {
    this.session = session;
    this.persistentClass = persistentClass;
  }
  public T search(Serializable id) {
     return session.load(persistentClass, id);
  }
  // outros metodos da interface Dao
}

Repare que ele recebe session como argumento, que poderia ser injetada por um container. Outra opção seria buscar a session de um singleton (o clássico HibernateUtil), mas a primeira maneira é bem mais elegante e testável. Repare que ainda temos os problemas de controle de transações: onde abrimos e comitamos? dentro do Dao? de dentro do injetor de dependências? de dentro da sua lógica de negócios? Nós costumamos fazer esse controle em um interceptador ou mesmo em um Filter de servlets, dependendo do framework MVC usado. Nosso filtro é semelhante com o recomendado pela documentação do hibernate.

E então podemos utilizar nosso DAO:

Dao<Cliente> clienteDao = new GenericHibernateDao<Cliente>(session);
clienteDao.persist(cliente);
Cliente c5 = clienteDao.search(5);

Para as entidades que você precisa de mais que um simples cria/le/atualiza/deleta, criamos uma nova interface:

interface ClienteHibernateDao extends Dao<Cliente> {
   List<Cliente> buscaTodosClientesQueDevemDinheiro();
}

E teríamos uma classe ClienteHibernateDao que estende GenericHibernateDao<Cliente> e implementa ClienteDao.

Meus colegas da easytech preferem abstrair também o tipo da chave primária:

interface Dao<T, I> {
  T search(I id);
  // ...
}

Dessa maneira você realmente ganha mais tipagem, já que no DAO anterior poderíamos passar qualquer objeto serializável como chave. Podemos refinar muito mais nossas classes de acesso a dados, mas até que ponto chegar?

Ficar abstraindo demais a sua camada de persistência pode levar a proliferação de centenas de pequenas classes que simplesmente não fazem nada, só delegam e delegam. Claro que existem casos em que abstrair para apenas delegar é interessante, diminuindo o acoplamento entre suas classes, porém isso pode chegar a um ponto que vai atrapalhar o desenvolvimento.

Nesta entrada do blog dos desenvolvedores do hibernate, o uso de camadas para abstrair as ferramentas de mapeamento objeto relacional são duramente criticadas.

E você, qual é a receita de bolo para o seu DAO? Até onde você o refina?

Fonte: Caelum – Paulo Silveira

Exemplo de DAO Genérico

Bom, no blog da Caelum a um tempo atras fizeram um POST sobre um DAO genérico, meio bizarro
Bom, eu uso um DAO genérico a algum tempo, mas o meu DAO genérico tm algumas features a mais do que o mostrado no post da caelum …

Neste exemplo eu ja deixo os metodos para fazer um query by example prontinho, usando a API de criteria do Hibernate …

bom, chega de enrolação, vamos a alguns exemplos …

primeiro, crio uma interface para este DAO …

package br.com.techoffice.site.dao;

import java.io.Serializable;
import java.util.List;

public interface TOBaseDao<T, PK extends Serializable> {
    public Class getObjectClass();
	public T save(T object);
	public T load(PK primaryKey);
    public T get(PK primaryKey);
	public List listAll();
	public List findByExample(final T example);
	public T findOneByExample(final T example);
	public List listAll(final int first,final int max);
	public int listAllPageCount();
	public List findByExample(final T example,final int first,final int max);
	public int findByExamplePageCount(final T example);
    public void update(T object);
    public void delete(T object);
    public void rebind(T object);
}

onde o método getObjectClass() deve retornar a classe de trabalho deste DAO, a mesma passada no parâmetro T quando a interface for estendida …

e a implementação desta interface, fica mais ou menos assim:

package br.com.techoffice.site.dao.impl;

import java.io.Serializable;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Example.PropertySelector;
import org.hibernate.type.Type;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import br.com.techoffice.site.dao.TOBaseDao;
import br.com.techoffice.site.dao.TODaoListener;

@Transactional(propagation = Propagation.REQUIRED, timeout = 20)
public abstract class TOBaseHibernateDao extends HibernateDaoSupport implements TOBaseDao<T, PK>, PropertySelector {
    private static final Log logger = LogFactory.getLog(TOBaseHibernateDao.class);
    private final Class objectClass;

    public TOBaseHibernateDao(final Class objectClass) {
        this.objectClass = objectClass;
    }

    @SuppressWarnings("unchecked")
    public Class getObjectClass() {
        return objectClass;
    }

    public int findByExamplePageCount(final T example) {
        final List l = findByExample(example);
        final Integer i = new Integer(l.size());
        return i.intValue();
    }

    public int listAllPageCount() {
        final List l = listAll();
        final Integer i = new Integer(l.size());
        return i.intValue();
    }

    /*
     * (non-Javadoc)
     *
     * @see br.ufrgs.hcpa.template.dao.GetNetBaseDao#findOneByExample(T)
     */
    public T findOneByExample(final T example) {
        final List res = findByExample(example, 0, 1);
        if ((res != null) && (res.size() == 1)) {
            return res.get(0);
        } else {
            return null;
        }
    }

    public T save(final T object) {
        try {
            final Session s = getSession(false);
            s.save(object);
            s.flush();
            return object;
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    public void update(final T object) {
        try {
            final Session s = getSession(false);
            s.update(object);
            s.flush();
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    public void rebind(final T object) {
        try {
            getSession(false).refresh(object);
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    public void delete(final T object) {
        try {
            getSession(false).delete(object);
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    @SuppressWarnings("unchecked")
    public T load(final PK primaryKey) {
        try {
            final Session s = getSession(false);
            final Object o = s.load(objectClass, primaryKey);
            return (T) o;
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    @SuppressWarnings("unchecked")
    public T get(final PK primaryKey) {
        try {
            final Session s = getSession(false);
            final Object o = s.load(objectClass, primaryKey);
            return (T) o;
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    @SuppressWarnings("unchecked")
    public List listAll() {
        try {
            final Session s = getSession(false);
            final Criteria c = s.createCriteria(objectClass);
            addOrderToCriteria(c);
            return c.list();
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

     @SuppressWarnings("unchecked")
    public List findByExample(final T example) {
        try {
            final Session s = getSession(false);
            final Criteria c = s.createCriteria(objectClass);
            c.add(Example.create(example).enableLike(MatchMode.ANYWHERE).ignoreCase().setPropertySelector(this));
            addOrderToCriteria(c);
            addPropertiedToCriteria(c, example);
            return c.list();
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    protected void addPropertiedToCriteria(final Criteria c, final T example) {
    }

    @SuppressWarnings("unchecked")
    public List findByExample(final T example, final int first, final int max) {
        try {
            final Session s = getSession(false);
            final Criteria c = s.createCriteria(objectClass);
            c.add(Example.create(example).enableLike(MatchMode.ANYWHERE).ignoreCase().setPropertySelector(this));
            addPropertiedToCriteria(c, example);
            addOrderToCriteria(c);
            if (first != 0) {
                c.setFirstResult(first);
            }
            if (max != 0) {
                c.setMaxResults(max);
            }
            return c.list();
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    @SuppressWarnings("unchecked")
    public List listAll(final int first, final int max) {
        try {
            final Session s = getSession(false);
            final Criteria c = s.createCriteria(objectClass);
            addOrderToCriteria(c);
            if (first != 0) {
                c.setFirstResult(first);
            }
            if (max != 0) {
                c.setMaxResults(max);
            }
            return c.list();
        } catch (final HibernateException ex) {
            TOBaseHibernateDao.logger.error(ex);
            throw convertHibernateAccessException(ex);
        }
    }

    protected void addOrderToCriteria(Criteria c) {
    }

    public boolean include(Object propertyValue, String propertyName, Type type) {
        if((propertyValue!=null) && (propertyValue instanceof String)){
            return !"".equals(((String)propertyValue).trim());
        }
        return propertyValue!=null;
    }
}

onde o método addOrderToCriteria, permite que subclasses deste DAO ordenem as consultas …
o método addPropertiedToCriteria permite que subclasses adicionem propriedades não incluidas pelo hibernate nas consultas …
e o método include combinado com o setPropertySelector da classe Example é uma melhoria adicionada a pouco tempo, que faz o mesmo que o addPropertiedToCriteria, mas de forma automática, ou seja, inclui as propriedades PK e FK também na QBE …

Bom, depois disto tudo, só falta criar o DAO para alguma entidade persistida pelo Hibernate, como por exemplo uma classe Curriculo …

Criamos a interface do nosso DAO:

package br.com.techoffice.site.dao;

import br.com.techoffice.site.data.Curriculo;

public interface CurriculoDao extends TOBaseDao{
}

e logo depois a implementação deste DAO:

package br.com.techoffice.site.dao.impl;

import net.java.dev.springannotation.annotation.Bean;
import br.com.techoffice.site.dao.CurriculoDao;
import br.com.techoffice.site.data.Curriculo;

@Bean(name="curriculoDao")
public class CurriculoDaoImpl extends TOBaseHibernateDao implements CurriculoDao {
	private static final long serialVersionUID = 1L;

	public CurriculoDaoImpl() {
        super(Curriculo.class);
    }
}

acho que era isto, o que acharam deste DAO genérico?
pela minha experiência, ele resolve de maneira estupidamente fácil em torno de 60% dos meus problemas de persistencia, nos outros 40% ai é necessário criar algum outro metodo de pesquisa especializado para cada situação …

mas acho que é esta a ideia das coisas genéricas, facilitar a maior parte do trabalho e permitir que a menor parte seja feita com um pouquinho de trabalho extra 😀 o que vocês acham?

Fonte: Blog do Urubatan

Java: como a serialização de objetos pode salvar sua aplicação desktop


Em um dos meus clientes é muito comum o desenvolvimento de aplicações Java voltadas para o ambiente desktop, aonde não raro enfrento problemas sérios de performance e consumo de recursos. O objetivo deste post é expor como usando o recurso de serialização de objetos oferecido pela plataforma Java consegui resolver (ou ao menos minimizar ao extremo) este desafio.

Imagine a seguinte situação: sua aplicação desktop acessa informações presentes em um banco de dados relacional. Dado que você precisa de produtividade, opta por usar uma ferramenta ORM como Hibernate ou JPA. Não resta dúvidas de que trata-se de um recurso maravilhoso, mas infelizmente traz consigo um custo de memória (precisamos carregar o motor de mapeamento objeto relacional, além disto, muitas vezes usamos cacheamento que, ao menos em parte, fica em memória) e performance (trata-se de mais uma camada no sistema). Em algumas situações causa um aumento no tempo de carregamento dos nossos sistemas tão grande que, não raro, você se vê questionando o ganho real do seu uso.

Imagine agora outra situação: sua aplicação trabalha apenas com JDBC e, com isto, sua performance é superior à obtida usando JPA ou Hibernate (apesar de sua existência neste caso ser mais infeliz), porém há limitações no número de conexões que podem ser feitas ao SGBD e, pior ainda, o tempo gasto estabelecendo a conexão com o SGBD é alto. Em situações como esta, o tal “ganho de performance” por não se estar usando Hibernate se perde totalmente, pois você nem tem o cacheamento automático provido pelo ORM.

Em ambos os casos, como resolver o problema? Simples: evitando ao máximo que seja necessário estabelecer QUALQUER tipo de conexão com o servidor.

Entra em cena a serialização de objetos

Todo sistema possui informações cuja alteração seja rara, ou seja, registros que apenas são inseridos no banco de dados e em raras situações tenham seus dados alterados. Como exemplos posso citar um cadastro de fornecedores ou endereços. Tratam-se de informações que são usadas, em 90% dos casos, apenas para consulta ou na composição de tipos mais complexos. Pergunte-se: é realmente necessário sempre pedir ao SGBD estes dados?

Nestes casos, a serialização de objetos cai como uma luva. E se você está em um ambiente corporativo, é possível inclusive fazer com que um único usuário beneficie todos os demais com um custo adicional mínimo. Vou ilustrar a situação usando como exemplo uma aplicação desktop que precise expor em um formulário uma caixa de seleção contendo a listagem de fornecedores presentes no banco de dados.

Vamos supor que esta nossa aplicação use o Hibernate. Neste caso, ao criar uma nova instância do formulário, precisamos obter a listagem de fornecedores seguindo o seguinte procedimento:

  1. É criada uma consulta no Hibernate usando criteria ou HQL
  2. Esta consulta é transformada em comandos SQL que serão enviados ao driver JDBC
  3. O driver JDBC envia a consulta para o SGBD
  4. O SGBD executa a consulta e retorna o resultado para o cliente
  5. O driver JDBC traduz o resultado enviado pelo SGBD para um objeto java.sql.Recordset
  6. O Hibernate cria novas instâncias da classe Fornecedor e, via reflexão, preenche todos os seus atributos
  7. E, finalmente, é retornada uma lista contendo o resultado para o cliente

Se esta for a primeira consulta feita pela aplicação, o seu usuário ainda vai ter de sofrer um pouquinho com o carregamento do SessionFactory do Hibernate.

Agora, quer ver como as coisas ficam mais simples usando serialização? Suponha que eu já tenha serializado esta lista de fornecedores em um arquivo presente em minha rede. O seguinte procedimento seria adotado.

  1. É verificado se o arquivo existe na rede.
  2. Se o arquivo existe, então este é desserializado em uma lista de fornecedores e retornado ao cliente.
  3. Se o arquivo não existe, execute o longo procedimento exposto acima novamente, com a diferença de que, agora, você serializará o resultado em arquivo no final.

Observe que interessante: não precisei carregar o Hibernate nem comunicar-me com qualquer servidor. Claro, se o arquivo não existisse, todo o processo citado acima seria necessário, porém em um ambiente de rede, só precisaria ser feito uma vez pelo primeiro usuário que necessitasse da lista de fornecedores. Dai pra frente, todos os demais usuários obteriam o ganho de performance que apresentei.

Mas o que é serialização de objetos

Ok, talvez você esteja apenas começando a aprender Java e não saiba o que é esta tal de serialização. Porcamente falando, serialização é o processo de salvar em arquivo um objeto presente na memória do seu computador.

Se eu quisesse salvar a minha listagem de fornecedores em um arquivo, o código abaixo daria conta do recado:
1

E, para transformar o meu arquivo em objeto, de novo apenas três linhas fariam o trabalho pra mim.
2

Detalhe: só podem ser serializados objetos que implementem a interface java.io.Serializable.

Omiti as excessões apenas para expor como é um recurso absurdamente fácil de ser usado.

Armadilhas a serem evitadas

O principal desafio desta abordagem é manter o cache sempre atualizado. Tenho duas soluções para este problema. A mais simples é de tempos em tempos apagar os arquivos de cache da rede. A mais complexa consiste em, toda vez que for persistir uma novo registro no banco de dados, apagar os arquivos de cache.

Dica: evite ao máximo chamar a função exist() da classe java.io.File, pois esta é absurdamente cara, visto que a cada chamada acessa o gerenciador de segurança do Java. Dado que o objetivo de qualquer sistema é expor os dados para o usuário, você pode sempre, ao verificar a existência do cache, escrever código similar ao exposto abaixo:

3

Outra armadilha: em um ambiente de rede, evite serializar os dados no HD local do usuário. Sempre que possível, opte por usar um drive de rede. Assim, caso seja necessário uma atualização do cache imediata, você, como administrador do sistema, em último caso sempre poderá apagar o arquivo de cache, forçando o cliente a recriá-lo novamente.

Fique atento também ao que será serializado. Dados que apenas ocasionalmente são consultados não são um bom alvo. Opte apenas por aquelas informações que são vitais ao uso do seu sistema e cuja atualização seja rara.

E, a principal armadilha: JAMAIS use esta técnica em entidades que precisem ser constantemente atualizadas na base de dados.

Padrão: buscando um único registro

Há situações em que não é necessário buscar uma lista de registros, mas apenas um, o que normalmente é feito executando uma consulta por chave primária. Nestes casos, adotei um padrão bastante simples. Crio um diretório na rede chamado cache e, dentro dele, um subdiretório que identifique o tipo da minha entidade. No caso de fornecedores, chamo este diretório, por exemplo, de /cache/fornecedor. No interior deste diretório armazeno arquivos cujo nome corresponda à chave primária da entidade que desejo buscar no banco de dados.

Mas se o Hibernate já possui sistema de cache, pra que usar serialização?


Como diriam os candidatos a presidente em um debate… esta é uma pergunta importantíssima.

Simples: porque a serialização, tal como estou expondo neste post, deve ser usada ANTES da primeira chamada ao Hibernate, pois assim, em algumas situações, consegue-se evitar o carregamento deste framework e, consequentemente, nosso usuário final terá um sistema muito mais leve e responsível.

Se sua aplicação vai ser executada em um servidor nem sei se o uso desta técnica trará algum resultado que realmente valha à pena.

Conclusões

Uso esta técnica para resolver os problemas de performance que enfrento em aplicações desktop, aonde normalmente os recursos computacionais podem ser mais limitados (as malditas “máquinas brancas”). O que pude observar é que, nestes casos, obtenho ganhos de performance astronômicos, pois a comunicação com o SGBD é reduzida a apenas o estritamente necessário.

Outro ganho que obtenho é o tempo de inicialização da aplicação, pois é muito comum neste momento ser necessária a execução de alguma consulta no SGBD. Sendo assim, esta é uma técnica que, ao menos por enquanto, cai como uma luva quando aplicada ao ambiente desktop.

Aos que queiram se aprofundar mais no assunto, sugiro a leitura deste post: “The Java serialization algorithm revealed”, que explica com detalhes o processo de serialização: http://www.javaworld.com/community/node/2915

Agora: sabem o que me choca nesta história toda? Este recurso maravilhoso oferecido pela plataforma é raríssimas vezes usado pelos desenvolvedores. Da pra acreditar???

Fonte: iTexto – Henrique Lobo Weissmann

Quando usar o fetch.LAZY e o fetch.EAGER

Alguns conceitos básicos:

  • EAGER – Tradução ->
  1. Ansioso
  2. Impaciente
  3. Ardente
  class NotaFiscal {
  ...
  @OneToMany(fetch=FetchType.EAGER)
  List items;
  }

Imagine que quando você usa o EAGER e dá um get num objeto, ele traz tudo que está dentro do objeto, ou seja, se há um relacionamento 1 para N, no objeto será carregado todas as referências(N) dele. Se sua aplicação depende de performance, este pode ser um problema, pois isto ocupará um grande espaço de memória carregando todas as listas/dependências do objeto.

  • LAZY – Tradução:
  1. Preguiçoso
  2. Indolente
  3. Lento
  4. Ocioso
  5. Vadio
  @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tabela_despesas", nullable = false)
    public Despesa getRelatorioDespesa() {
        return this.relatorioDespesa;
    }

Desse modo, quando acessamos o objeto ele não traz instantaneamente todas as dependências. Somente quando precisamos do atributo dependente é que a pesquisa (select ou JOIN) é feito, economizando memória. Para que o LAZY faça este select/JOIN é necessário declarar o fetch, dizer como será a pesquisa, se via Selec ou JOIN e você gera então a consulta.

O Hibernate tira proveito de proxies dinâmicas: ele te devolve objetos que fingem ser listas nesse caso, e quando você invoca algum método deles, o Hibernate então faz a respectiva query para carregar o relacionamento. Caelum

Lazy diz QUANDO trazer.lazy=”true” – Traga quando eu precisar ( ou seja. Quando eu acessar ) lazy = “false” – Traga junto com o objeto principal

  • Fetch – Tradução->
  1. buscar
  2. ir buscar
  3. trazer

Fetch diz COMO trazer.fetch = “select” – Faça um select pra pegar esse atributo fetch=”join” – Faça um join com o objeto principal e traga junto com ele. Essa opção ANULA a opção lazy = “true” EAGER, seria equivalente lazy = false.

  1. @Fetch( FetchMode.SELECT )
  2. @Fetch( FetchMode.JOIN )

Todos os relacionamentos *ToOne sãoEAGER, e os *ToMany são LAZY, isso porque relações *toMany são provavelmente mais custosas, trazendo mais objetos para a memória. Caelum

————————————————————————-
Problemas com lazy init (LazyInitializationException)?

Session session = sessionFactory.openSession();
NotaFiscal nf = (NotaFiscal) session.load(NotaFiscal.class, 42);
session.close();

List items = nf.getItems();
System.out.println("numero de pedidos dessa nota:" + items.size());

Esse código tem o seguinte resultado:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection - no session or session was closed.

Utilize o open session in view: Sempre fechar a sessão ao término do trabalho. Mas e quando estamos trabalhando na Web? Após pegarmos os dados necessários no nosso controlador, fechamos a sessão e passamos os objetos ao JSP através de atributos. O JSP, ao acessar um getter do seu objeto para fazer um loop, como ${notaFiscal.items}, recebeLazyInitializationException da mesma forma. Em um primeiro momento o desenvolvedor muda o relacionamento para EAGER, mas isso gera uma enorme sobrecarga, pois provavelmente em muitos lugares não era necessário carregar todos os itens da compra sempre que uma determinada nota fiscal é requisitada. Como então evitar a LazyInitializationException sem modificar o relacionamento paraEAGER? Open Session In View A solução é manter a session aberta durante a renderização da camada de visualização, ou como o Hibernate chama esse pequeno padrão: open session in view. A idéia é bastante simples: a sessão deve ser mantida aberta até o fim da renderização do JSP (ou de qualquer outra camada de apresentação). Isso pode ser obtido através da implementação de um Servlet Filter, algum tipo de interceptador do seu framework preferido ou até mesmo aspectos. O Spring foi sem dúvida um dos primeiros frameworks a já trazer classes para isso embutidas (assim como também foi o primeiro a fazer o wrap da HibernateException dentro de uma exceçãounchecked, pois até o Hibernate 2.x essa exceção era checked). Há as classesOpenSessionInViewInterceptor e sua análoga OpenEntityManagerInViewInterceptor. No VRaptor, além de você pode usar os componentes embutidos do Spring, já existem componentes que fazem o mesmo trabalho (ver componentes embutidos). Leia a matéria completa no blog da CAELUM: http://blog.caelum.com.br/2009/10/13/enfrentando-a-lazyinitializationexception-no-hibernate/  Outro problema:

Hibernate – could not initialize proxy – no Session
  1. 09:15:11,883 ERROR LazyInitializationException:19 – could not initialize proxy – no Session
  2. org.hibernate.LazyInitializationException: could not initialize proxy – no Session
  3.     at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:57)
  4.     at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:111)
  5.     at org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer.invoke(CGLIBLazyInitializer.java:150)
  6.     at org.iprogramming.model.persistence.dto.Person$$EnhancerByCGLIB$$4dfa7473.getName(<generated>)

Essa exception ocorre porque voce fechou a sessão do hibernate (ou entitymanager do JPA usando hibernate). Provavelmente voces estao fechando a sessao/entityManager antes de renderizar a pagina, isso é, antes de fazer o dispatch!

————————————————————————-
Leia a discussão sobre este problema e outras soluções no GUJ:
http://www.guj.com.br/java/60474-hibernate—could-not-initialize-proxy—no-session
http://www.guj.com.br/java/23319-hibernate-3—-orghibernatelazyinitializationexception-could-not-initialize-proxy—the-owning-se

Fonte: Jardelmorais