Arquivos de sites

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

Anúncios

jQuery – O método live()

No capítulo anterior, nós usamos os métodos bind() e unbind() para anexar e desanexar manipuladores de eventos a vários elemento na página. Isso funciona bem para elementos dos quais ja existem, mas e se você  quiser que seu manipulador de evento seja anexado para elementos futuros também? Normalmente você teria que fazer isso manualmente, sobre a criação de novos elementos, e isso continuaria possível. Porém usando o método live(), você pode informar ao jQuery para anexar o seu manipulador de evento para qualquer elemento futuro que combine com o seu seletor original, sem precisar levantar um dedo. Deixe-me primeiro mostrar a você um exemplo onde nós usamos o método bind(), e então substituímos ele com o método live(), para mostrar a diferença:

<div id="divTestArea1">
        <a href="javascript:void(0);" onclick="AddBox();">Add box</a>
        <div class="test">This is a box</div>
</div>

<script type="text/javascript">
$(function()
{
        $(".test").bind("mouseover", function()
        {
                $(this).css("background-color", "blue");
        }).bind("mouseout", function()
        {
                $(this).css("background-color", "white");
        });
});

function AddBox()
{
        var div = $("<div></div>").addClass("test").text("Another box");
        $("#divTestArea1").append(div);
}
</script>

OK, esse exemplo pode parecer um pouco complicado, mas na verdade não é. Deixe me explica-lo. Nós temos um link, qual irá chamar o método javascript AddBox(), e então nós temos uma diz com a classe “test”. O método AddBox() simplesmente adicionar outra div na página. No evento read, nós selecionamos todos os elementos com a classe “test” e então nós vinculamos um manipulador para dois dos eventos: Os eventos mouseover e mouseout , quando nós mudamos a cor do elemento invocando o evento. Tente o exemplo no seu navegador. A primeira div terá o efeito mouseover, mas se você clicar no link para adicionar mais caixas, elas não terão o mesmo efeito. A razão é bastante óbvia: Nós anexaremos os eventos antes dessas novas caixas serem criadas.

Agora tente o seguinte exemplo em vez disso. Eu apenas modifiquei dias palavras nisso: As dias chamadas a bind() foram substituídas com chamadas a live():

<div id="divTestArea2">
        <a href="javascript:void(0);" onclick="AddBox();">Add box</a>
        <div class="test">This is a box</div>
</div>

<script type="text/javascript">
$(function()
{
        $(".test").live("mouseover", function()
        {
                $(this).css("background-color", "blue");
        }).live("mouseout", function()
        {
                $(this).css("background-color", "white");
        });
});

function AddBox()
{
        var div = $("<div></div>").addClass("test").text("Another box");
        $("#divTestArea2").append(div);
}
</script>

Agora se você puder rodar esse exemplo, você verá que mesmo você adicionando novos elementos após a página ser carregada, jQuery irá automaticamente anexar o manipulador de eventos a eles para você. O método live() funciona como o bind() em todos os outros aspectos, então cheque os capítulos anteriores para mais informações sobre isso. O mesmo funciona para o método die(), que funciona como o método unbind(), mas deve ser usado para casos onde o método live() foi usado.

Fonte: jquery-tutorial.net

jQuery – Os métodos before() e after()

No capítulo anterior, nós usamos os métodos append() e prepend() para inserir coisas dentro de um elemento, mas em alguns casos, nós precisamos inserir coisas antes ou depois de um ou vários elementos em vez disso. O jQuery tem os métodos befoer() e after() apenas para esse propósito, e eles são tão fáceis de usar. Veja esse exemplo:

<a href="javascript:void(0);" onclick="$('input.test1').before('<i>Before</i>');">Before</a>   
<a href="javascript:void(0);" onclick="$('input.test1').after('<b>After</b>');">After</a>
<br /><br />
<input type="text" value="Input 1" name="txtInput1" /><br />
<input type="text" value="Input 2" name="txtInput2" /><br />

Dependendo em qual dos dois links você clicou, uma tag itálico ou uma negrito será inserida antes ou depois de cada elemento input na página usando a classe “test1”. Assim como append() e prepend(), ambos after() e before() permitem você usar strings HTML, elementos DOM e objetos jQuery como parâmetros e uma quantidade infinita deles também. Nós vamos demonstrar isso no próximo exemplo:

<a href="javascript:void(0);" onclick="InsertElements();">Insert elements</a>
<br /><br />
<span id="spnTest2">Hello world? </span>
<script type="text/javascript">
function InsertElements()
{
        var element1 = $("<b></b>").text("Hello ");
        var element2 = "<i>there </i>";
        var element3 = document.createElement("u");
        element3.innerHTML = "jQuery!";   
        $("#spnTest2").after(element1, element2, element3);
}
</script>

Neste exemplo, nós criamos um objeto jQuery, uma string HTML e um elemento JavaScript DOM, e então nós usamos o método after() para inserir todos eles depois da nossa tag span. Claro, o método before() poderia ter sido usado exatamente da mesma maneira.

Existem variações dos métodos before() e after(), chamados insertBefore() e inserAfter(). Eles fazem praticamente a mesma coisa, mas eles fazem isso ao contrário, então ao invés de os chamarem nos elementos que devemos inserir dados antes ou depois, com um parâmetro do que é para ser inserido, você faz exatamente o oposto. Qual método usar obviamente depende da situação, mas aqui está um exemplo mostrando a você como usar ambos:

<a href="javascript:void(0);" onclick="InsertElementsBefore();">Insert elemenets</a>
<br /><br />
<span id="spnTest3">Hello world? </span>
<script type="text/javascript">
function InsertElementsBefore()
{       
        $("#spnTest3").before($("<i></i>").text("before() "));
        $("<b></b>").text("insertBefore() ").insertBefore("#spnTest3");
}
</script>

Neste exemplo, nós inserimos os itens antes da tag span, mas você poderia com certeza fazer exatamente a mesma coisa usando after() e insertAfter(), se você deseja inserir depois do elemento alvo. Como você pode ver, o resultado é o mesmo – apenas a ordem do que nós fazermos difere.

Fonte: jquery-tutorial.net

jQuery – Os métodos append() e prepend()

Adicionar novos objetos a um element existente é muito fácil com jQuery. Aqui estão métodos para anexar ou prefixar, recebendo HTML em formato string, elementos DOM e ojbetos jQuery como parâmetros. No próximo exemplo, você verá como é fácil inserir novos elementos em uma lista, usando ambos os métodos append() e prepend():

<a href="javascript:void(0);" onclick="$('#olTestList1').append('<li>Appended item</li>');">Append</a>   
<a href="javascript:void(0);" onclick="$('#olTestList1').prepend('<li>Prepended item</li>');">Prepend</a>
<ol id="olTestList1">
        <li>Existing item</li>
        <li>Existing item</li>
</ol>

Nós temos dois links: O primeiro irá anexar um item a lista, significando que o novo item será inserido como último item. O outro link irá prefixar um link a lista, o que significa que o novo item será inserido como o primeiro item da lista. Neste exemplo, nós simplesmente inserimos um pedaço de HTML, mas nós poderíamos  ter gerado os novos itens com jQuery também, ou criado eles através do código JavaScript padrão e elementos DOM. De fato, ambos os métodos append() e prepend() recebem uma quantidade infinita de novos elementos como parâmetros. No próximo exemplo, nós vamos demonstrar isso também como a habilidade para adicionar elementos de várias formas:

<a href="javascript:void(0);" onclick="AppendItemsToList();">Append items</a>   
<ol id="olTestList2"></ol>
<script type="text/javascript">
function AppendItemsToList()
{
        var item1 = $("<li></li>").text("Item 1");
        var item2 = "<li>Item 2</li>";
        var item3 = document.createElement("li");
        item3.innerHTML = "Item 3";
        
        $("#olTestList2").append(item1, item2, item3);
}
</script>

Como você pode ver, o item1 é um elemento gerado por jQuery, o item2 é uma simples string HTML e o item3 é um elemento gerado por JavaScript DOM.Todos eles foram anexado a lista usando a mesma chamada e claro isso deveria funcionar para o método prepend() também.

Existem variações dos métodos append() e prepend(), chamados appendTo() e prependTo(). Eles fazem praticamente a mesma coisa, mas eles fazem isso ao contrário, então em invés de os chamarem nos elementos que você deseja anexar/prefixar, com um parâmetro do que é para ser anexado/prefixado, você faz exatamente o oposto. Qual usar obviamente depende da situação, mas aqui está um exemplo mostrando a você como usar ambos:

<a href="javascript:void(0);" onclick="PrependItemsToList();">Prepend items</a>   
<ol id="olTestList3"></ol>
<script type="text/javascript">
function PrependItemsToList()
{       
        $("#olTestList3").prepend($("<li></li>").text("prepend() item"));
        $("<li></li>").text("prependTo() item").prependTo("#olTestList3");
}
</script>

Neste exemplo, nós prefixamos os itens, mas você poderia com certeza fazer a mesma coisa usando append() e appendTo(). Como você pode ver, o resultado é o mesmo – apenas a ordem do que nós fazemos difere.

Fonte: jquery-tutorial.net