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

Ordenando Lista de Objetos em Java

Pessoal, andei apanhando um pouco no trabalho, e achei essa solução, para ordenar um ArrayList,
segue abaixo o que salvou minha vida ahuahuahuaha :

Quem nunca na sua vida de programador, seja iniciando pela linguagem de programação C ou direto pelo Java, não enfrentou alguns problemas com Segmentation fault e NullPointException ao trabalhar-se com vetores, principalmente por se acessar índices que não existiam. Na linguagem de programação C não existe muita escapatória para esses casos, além de implementar toda a lógica para a manipulação desses vetores. Um dos exercícios clássicos em C é o de ordenar um vetor em ordem crescente ou decrescente, utilizando-se de alguma lógica com fors e ifs.

Ao iniciar o estudo em Java, também aprendemos a utilizar primeiramente os vetores e enfrentamos os mesmos problemas que no C, até fazemos os mesmos exercícios já feitos em C sobre vetores. Mas ai pensamos, Java sendo uma linguagem de mais alto nivel que o C, será que não existe uma solução mais elegante? A resposta vem da Collections Framework, que é uma API robusta criada pela Sun que possui diversas classes que representam estruturas de dados avançadas, como ArrayList e LinkedList, e funções úteis para se trabalhar com vetores.

O objetivo desse artigo não é dar toda explicação de como utilizar a sintaxe da API Collections, sendo os dois primeiros parágrafos uma breve introdução sobre o assunto, mas sim de como ordenar uma lista de objetos em Java sem ter que implementar nenhuma lógica mirabolante. Uma lista de objetos em Java pode ser facilmente ordenada utilizando o método sort da API Collections. Como exemplo iremos criar uma lista de strings e adicionar algumas palavras nela, depois iremos imprimir essa lista para ver sua ordem. Depois executaremos o método sort para ordenar a lista e imprimiremos novamente a lista para comparar o resultado.

List<String> lista = new ArrayList<String>();
lista.add("fogo");
 lista.add("agua");
 lista.add("vento");
 lista.add("terra");
for(String i : lista){
 System.out.println(i);
 }
Collections.sort(lista);
 System.out.println("Ordenando a lista:");
for(String i : lista){
 System.out.println(i);
 }

Resultado:

fogo
agua
vento
terra
Ordenando a lista:
agua
fogo
terra
vento

Como pode ser visto acima, a lista foi reordenada em ordem crescente. Mas como o método sort sabia como organizar a lista? Ele precisa utilizar um método int compareTo(Object) para poder ordenar a lista, que retorna zero, se o objeto comparado for igual a este objeto, um número negativo, se este objeto for menor que objeto dado, e um número positivo, se este objeto for maior que o objeto dado. Este método está definido na interface Comparable, que deve ser implementado pela classe que será ordenado em uma lista. Não é necessariamente obrigatório que a classe implemente a interface Comparable, ao chamar o método sort pode também ser passado como parâmetro além da lista que será ordenada um método que fará a ordenação.

Entendemos como à ordenação é feita, mais ainda assim não implementamos a interface Comparable e nenhuma logica para a ordenação. Como a lista pode ser ordenada com o método sort? A resposta é que a classe string já implementa a interface Comparable que ordena em ordem alfabética seus elementos. Outras classes em Java que implementam essa interface são: BigDecimal, BigInteger, Byte, ByteBuffer, Character, CharBuffer, Charset, CollationKey, Date, Double, DoubleBuffer, File, Float, FloatBuffer, IntBuffer, Integer, Long, LongBuffer, ObjectStreamField, Short, ShortBuffer e URI que podem ser ordenadas simplesmente utilizando-se o método sort.

Agora chegamos ao caso se quisermos ordenar uma lista de objetos de uma classe que nós mesmos criamos. Para isso a nossa classe deve implementar a interface Comparable. Utilizaremos como exemplo a classe abaixo chamada carro, que contém apenas dois atributos, cilindrada e cor, e um construtor que recebe esses atributos.

public class Carro {
private String cor;
 private int cilindrada;
public Carro(String cor, int cilindrada) {
 super();
 this.cor = cor;
 this.cilindrada = cilindrada;
 }
public String getCor() {
 return cor;
 }
public void setCor(String cor) {
 this.cor = cor;
 }
public int getCilindrada() {
 return cilindrada;
 }
public void setCilindrada(int cilindrada) {
 this.cilindrada = cilindrada;
 }
 }

Realizaremos agora as modificações necessárias na nossa classe carro para que possamos ordenar uma lista da nossa classe utilizando o método sort. Primeiramente a nossa classe deve implementar a intarface Comparable e consequentemente implementar o método sort, lembrando que este método retorna zero se o objeto é igual, um numero negativo se for menor e um numero positivo se for maior. Iremos também decidir como queremos a ordenação da nossa lista de carros seja feita, a ordenação será feita em ordem decrescente de cilindrada, e em caso de ter igual será ordenado em ordem alfabética de cor. A classe finalizada por ser vista abaixo.

public class Carro implements Comparable {
private String cor;
 private int cilindrada;
public Carro(String cor, int cilindrada) {
 super();
 this.cor = cor;
 this.cilindrada = cilindrada;
 }
public String getCor() {
 return cor;
 }
public void setCor(String cor) {
 this.cor = cor;
 }
public int getCilindrada() {
 return cilindrada;
 }
public void setCilindrada(int cilindrada) {
 this.cilindrada = cilindrada;
 }
public int compareTo(Carro carro) {
 if(this.cilindrada > carro.cilindrada){
 return -1;
 }
 else if(this.cilindrada < carro.cilindrada){
 return 1;
 }
 return this.getCor().compareToIgnoreCase(carro.getCor());
 }
 }

Para mostrar que a ordenação realmente funcionou, iremos fazer um teste, onde criaremos uma lista de carros, adicionaremos alguns carros há lista, alguns com mesma cilindradas e cores diferentes. Depois iremos imprimir essa lista de carros, executar o método sort e exibir de novo a lista para ver se a ordenação realmente ocorreu.

List carros = new ArrayList();
carros.add(new Carro("Azul",500));
 carros.add(new Carro("Verde",300));
 carros.add(new Carro("Laranja",700));
 carros.add(new Carro("Marrom",300));
 carros.add(new Carro("Amarelo",700));
for(Carro c : carros){
 System.out.println("Carro de cor "+c.getCor()+" e "+c.getCilindrada()+" cilindradas.");
 }
Collections.sort(carros);
 System.out.println("Ordenando a lista:");
for(Carro c : carros){
 System.out.println("Carro de cor "+c.getCor()+" e "+c.getCilindrada()+" cilindradas.");
 }

Resultado:

Carro de cor Azul e 500 cilindradas.
 Carro de cor Verde e 300 cilindradas.
 Carro de cor Laranja e 700 cilindradas.
 Carro de cor Marrom e 300 cilindradas.
 Carro de cor Amarelo e 700 cilindradas.
 Ordenando a lista:
 Carro de cor Amarelo e 700 cilindradas.
 Carro de cor Laranja e 700 cilindradas.
 Carro de cor Azul e 500 cilindradas.
 Carro de cor Marrom e 300 cilindradas.
 Carro de cor Verde e 300 cilindradas.

Como esperado a ordenação funcionou corretamente. Era isso que este artigo proponha a se tratar, pode ser algo simples para algumas pessoas, mas para quem não conhece pode ser de grande ajuda, facilitando muito o seu trabalho.

Fonte: blog.sippulse.com – Jonas Diogo

Tutorial Google Maps Android API v2

Antes de começar a trabalhar com a API, você vai precisar baixar a API  e obter a chave. Tanto a API quanto a chave estão disponíveis gratuitamente.

Configurando o ambiente

O Google Maps API Android V2 é distribuído como parte do Google Play services SDK . Siga os passos abaixo para instalar o Google Play Services SDK para o desenvolvimento com o Eclipse:

1. Selecione no menu do ecplise Window > Android SDK Manager

2. Vá até a parte inferior da lista de pacotes, selecione Extras> Google Play Services, e instale-o;

3. Copie o <android-sdk-folder>/extras/google/google_play_services/libproject/google-play-services_lib  library project para a pasta onde você criou seu projeto android;

4. Usando o Eclipse, importe o projeto de biblioteca em sua workspace. Clique em File> Import, selecione Android > Existing Android Code into Workspace  e vá para a cópia do projeto de biblioteca Google Play Service para importá-lo;

5. Vá em Properties do seu projeto (Clique com o botão direito no seu projeto) e selecione o menu “Android“;

6. Clique no botão [Add…] e na caixa de diálogo “Project Selection” selecione o projeto google-play-services-lib que foi importado anteriormente;

Tutorial Google Maps para Android

Nota: O Google Play Services não é compatível com o emulador Android

 

Obtendo a chave Map Api Key

O Google Maps API v2 Android usa um novo sistema de gerenciamento de chaves. Chaves existentes de um aplicativo Android Google Maps v1 não vão funcionar com a API v2.

Obter uma chave para a sua aplicação requer várias etapas. Estes passos são descritos aqui, e descritos em detalhe nas seções seguintes.

1. Recuperar informações sobre o certificado de sua aplicação (SHA-1 fingerprint).

A chave do Google Maps API é baseada em um pequeno formulário de certificado digital do seu aplicativo, conhecido como SHA-1 fingerprint. A fingerprint é uma seqüência de texto único, gerado a partir do algoritmo comumente usado SHA-1 hashing. Porque a fingerprint é única, o Google Maps pode usa-lo como uma forma de identificar a sua aplicação.

Você pode gerar a chave a partir de dois tipos de certificados:

Debug certificate: 

O certificado é apenas para uso de um aplicativo que você está testando, você não pode publicar um aplicativo que está assinado com um certificado de depuração. O certificado de depuração é descrito com mais detalhes na seção Signing in Debug Mode da Documentação de desenvolvedor Android. Você pode gerar uma chave de API a partir deste certificado, mas apenas usar a chave para o teste, nunca para a produção.

Exibindo o fingerprint para chave de debug:
1.1 Localize o arquivo de debug keystore. O nome do arquivo é debug.keystore, e é criado a primeira vez que você cria seu projeto. Por padrão, ele é armazenado no mesmo diretório do seu dispositivo AVD:
Usando o Eclipse selcione Windows > Prefs > Android > Build  para verificar o caminho completo (Default debug keystore);
1.2 Usando o Terminal do windows (cmd) navegue até a pasta bin do jdk da sua máquina para ter acesso aos comandos Keytool
1.3 Execute a seguinte linha de comando subistituindo o caminho do arquivo debug.keystore pelo seu visualizado anteriormente:
keytool -list -v -keystore "C:\Users\your_user_name\.android\debug.keystore" -alias androiddebugkey -storepass android -keypass android
Caso você tenha ma exceção de formato no keystore, você deve alterar as configurações regionais do seu Windows colocando Formato e Local para Estados Unidos

1.4 Você deverá ver uma saída semelhante a esta e dentre as informações você já pode ver seu SHA-1 fingerprint

 Alias name: androiddebugkey  Creation date: Jan 01, 2013  Entry type: PrivateKeyEntry  Certificate chain length: 1  Certificate[1]:  Owner: CN=Android Debug, O=Android, C=US  Issuer: CN=Android Debug, O=Android, C=US  Serial number: 4aa9b300  Valid from: Mon Jan 01 08:04:04 UTC 2013 until: Mon Jan 01 18:04:04 PST 2033  Certificate fingerprints:       MD5:  AE:9F:95:D0:A6:86:89:BC:A8:70:BA:34:FF:6A:AC:F9       SHA1: BB:0D:AC:74:D3:21:E1:43:07:71:9B:62:90:AF:A1:66:6E:44:5D:75       Signature algorithm name: SHA1withRSA       Version: 3

Release certificate:

  •  Este certificado pode ser usado com o aplicativo que você queira publicar em produção.

Depois de decidir qual o certificado correto para suas necessidades, você pode obter a chave seguindo este outro tutorial…
2. Registrar um projeto no Google APIs Console e adicionar a API do Google Maps como um serviço para o projeto.

2.1 Acesse Google APIs Console

2.3 Se você não usou o Google APIs Console antes, você será solicitado a criar um projeto que você usará para controlar o uso do Google Maps API Android. Clique em Create Project e crie um novo projeto chamado Projeto API. Na próxima página, este nome aparece no canto superior esquerdo. Para renomear ou gerenciar o projeto, clique em seu nome.
Se você já está usando o Google APIs Console, você vai ver imediatamente uma lista de seus projetos existentes e os serviços disponíveis. Ainda é uma boa ideia usar um novo projeto para o Google Maps API Android, portanto, selecione o nome do projeto no canto superior esquerdo e, em seguida, clique em Create.

3. Uma vez que você tem um projeto definido, você pode solicitar uma ou mais chaves.

3.1Você deverá ver uma lista de APIs e serviços na janela principal. Se você não estiver vendo isso, selecione Services da barra de navegação à esquerda.

3.2 Na lista de serviços exibidos no centro da página, role para baixo até ver o Google Maps API v2 Android. Clique no indicador de “interruptor”, de modo que ele está ligado.

3.3 Aceite os termos de Serviços e estará pronto para ter uma Maps API Key.

3.4 Na barra de navegação à esquerda, clique em API Access.

3.5 Clique no botão [Create New Android Key…]

3.6 Na caixa de diálogo, digite o  SHA-1 fingerprint, em seguida, um ponto e vírgula, em seguida, o nome do pacote do aplicativo. Por exemplo:

BB:0D:AC:74:D3:21:E1:43:67:71:9B:62:91:AF:A1:66:6E:44:5D:75;com.frameworksystem.android.mapexample

O Google APIs Console responde exibindo-chave para aplicativos Android (com certificados), seguido por uma chave, por exemplo:

AIzaSyBdVl-cTICSwYKrZ95SuvNw7dbMuDt1KG0

4. Finalmente, você pode adicionar a sua chave para a sua aplicação e iniciar o desenvolvimento.

 

Adicionando a API Key em sua aplicação

O passo final é adicionar a chave da API para a sua aplicação.

1. Em AndroidManifest.xml, adicione o seguinte elemento como um filho do elemento <application>, inserindo-lo antes da tag de fechamento </ application>:

<meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="your_api_key"/>

2. substitua “your_api_key” Pela sua chave API Key obtida anteriormente.

3. Adicione os seguintes elementos para o seu AndroidManifest.xml. Substitua com.frameworksystem.android.mapexample com o nome do pacote da sua aplicação.

<permission
        android:name="com.example.mapdemo.permission.MAPS_RECEIVE"
        android:protectionLevel="signature"/>
<uses-permission android:name="com.frameworksystem.android.mapexample.permission.MAPS_RECEIVE"/>

4. Especifique as seguintes permissões no AndroidManifest.xml substituindo com.frameworksystem.android.mapexample pelo pacote da sua aplicação:

 

<uses-permission android:name=”android.permission.INTERNET” />
<uses-permission android:name=”android.permission.ACCESS_COARSE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_FINE_LOCATION” />
<uses-permission android:name=”android.permission.ACCESS_NETWORK_STATE” />
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE”/>
<uses-permission android:name=”com.google.android.providers.gsf.permission.READ_GSERVICES”/>

<permission
android:name=”br.com.cadastroindustrial.permission.MAPS_RECEIVE”
android:protectionLevel=”signature”/>
<uses-permission android:name=”com.frameworksystem.android.mapexample.permission.MAPS_RECEIVE”/>

<uses-feature
android:glEsVersion=”0x00020000″
android:required=”true”/>

Desenvolvendo um Mapa

 

1.  Implement a seguinte Activity:

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;

public class MainActivity extends Activity {
  private LatLng frameworkSystemLocation = new LatLng(-19.92550, -43.64058);
  private GoogleMap map;

  @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    map = ((MapFragment) getFragmentManager().findFragmentById(R.id.map))
        .getMap();
    Marker frameworkSystem = map.addMarker(new MarkerOptions()
                                               .position(frameworkSystemLocation)
                                               .title("Framework System"));
 // Move a câmera para Framework System com zoom 15.
    map.moveCamera(CameraUpdateFactory.newLatLngZoom(frameworkSystemLocation , 15));
    map.animateCamera(CameraUpdateFactory.zoomTo(10), 2000, null);
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
  }

}

 

2. Implemente o seguinte layout para a Activity

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</RelativeLayout>

 

Observações !!!!! :

Pessoal, as estruturas de Fragment do android foram criadas na versão 3.0.
Para aplicações feitas com versões anteriores do android existe a biblioteca android-support-v4.jar que oferece suporte a estrutura de Fragment e outras novas implementações para as versões anteriores do android.

Para adicionar a biblioteca de suporte em sua aplicação, usando o eclipse vá em Properties do seu projeto (Clique com o botão direito no seu projeto) e selecione Android Tools > Add Support Library… marque Accept All e clique no botão [ Install ]

Feito isso sua Activity agora deve estender de FragmentActivity e para instanciar o objeto map (private GoogleMap map) deverá ser feito as seguintes alterações:

map = ((SupportMapFragment) getSupportFragmentManager().findFragmentById(R.id.map)).getMap();

———————————————————————————————————-

fonte: Framework System – Geraldo Marcelo