Introdução ao Java Architecture for XML Biding (JAXB)

Olá, novamente um post simples, porém com uso efetivo no desenvolvimento de software. Muitas aplicações Java utilizam arquivos eXtensible Markup Language (XML) para inúmeras funcionalidades, como armazenamento de configurações de um software e informações características dos usuários.

Este post tem por objetivo introduzir com exemplos em código fonte, o uso do Java Architecture for XML Biding (JAXB), uma biblioteca que possibilita a conversão de dados contidos em um arquivo XML para objetos Java e objetos Java para XML.

O JAXB também fornece ferramentas para criação de conteúdo XML Schema Definition (XSD) e geração de classes Java utilizando conteúdo XSD. O XSD é um tópico que não será abordado neste post.

Uma outra característica, o JAXB também pode ser inserido em aplicações Android, porém, não vem como conteúdo nativo da plataforma, portanto é necessário adicionar uma biblioteca externa, mas há outros métodos para trabalhar com conteúdo XML tanto nativos como externos, alguns são mais simples e aderem mais a tendência de aplicações que ocupem pouco espaço em disco, mas isto é um post para outro assunto.

Apesar de existirem métodos com propósitos similares em Java ao JAXB, tais como Simple API for XML (SAX) e Document Object Model (DOM), o JAXB acaba sendo uma alternativa interessante e produtiva, pois trabalha com annotations e é possível uma prototipagem simples e efetiva para solução do problema.

Antes de conhecermos annotations básicas usadas no JAXB, um exemplo de arquivo XML descritor que iremos trabalhar:

Arquivo XML descritor.

Arquivo XML descritor.

A figura acima, representa um exemplo de XML da qual iremos trabalhar. Basicamente é um cadastro fictício de uma empresa, que possui um conteúdo de fácil identificação. Note que em telefones, temos dois telefones, dos quais o segundo telefone não contém um ddd. Devemos estar atento a este exemplo, principalmente por não ser um campo necessário. Verificando o código a visualização fica trivial.

Uma página interessante para validarmos um arquivo XML é o W3Schools, link:

http://www.w3schools.com/xml/xml_validator.asp

Agora, vamos conhecer as principais anotações que serão utilizadas no tutorial para trabalhar com este conteúdo XML:

  • @XmlRootElement – Conteúdo esperado de nível superior, ou seja, nome da classe geralmente;
  • @XmlAccessorType – Indica onde as anotações do XML estão: atributos ou métodos da classe;
  • @XmlAttribute – O valor contido em um campo será atributo XML;
  • @XmlType – Classe que mapeia informações específicas;
  • @XmlElement – Atributos ou métodos;
  • @XmlElementWrapper – Objetos do tipo List.

Alguns nomes de métodos que devemos conhecer:

  • Marshal – Transforma um objeto Java em um XML;
  • Unmarshal – Transforma um XML em um objeto Java.

Em JAXB precisamos instanciar um objeto determinado como JAXBContext que fornecerá Marshaller ou Unmarshaller, interfaces do pacote javax.xml.bind. O código abaixo representa a classe Telefone, fique atento para o campo “required = false” para o ddd, que não será obrigatório.

package br.com.tutorials.content;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "telefone")
@XmlAccessorType(XmlAccessType.FIELD)
public class Telefone {
 @XmlAttribute(name = "ddd", required = false)
 private String ddd;
 @XmlElement(name = "num", required = true)
 private Long num;

public String getDdd() {
 return ddd;
 }

public void setDdd(String ddd) {
 this.ddd = ddd;
 }

public Long getNum() {
 return num;
 }

public void setNum(Long num) {
 this.num = num;
 }
}

O código abaixo representam Endereco.

package br.com.tutorials.content;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "endereco")
@XmlAccessorType(XmlAccessType.FIELD)
public class Endereco {

 @XmlAttribute(name = "cep", required = true)
 private String cep;
 @XmlAttribute(name = "num", required = true)
 private String num;
 @XmlAttribute(name = "pais", required = true)
 private String pais;

 @XmlElement(name = "estado", required = true)
 private String estado;
 @XmlElement(name = "cidade", required = true)
 private String cidade;
 @XmlElement(name = "rua", required = true)
 private String rua;

public String getCep() {
 return cep;
 }

public void setCep(String cep) {
 this.cep = cep;
 }

public String getNum() {
 return num;
 }

public void setNum(String num) {
 this.num = num;
 }

public String getPais() {
 return pais;
 }

public void setPais(String pais) {
 this.pais = pais;
 }

public String getEstado() {
 return estado;
 }

public void setEstado(String estado) {
 this.estado = estado;
 }

public String getCidade() {
 return cidade;
 }

public void setCidade(String cidade) {
 this.cidade = cidade;
 }

public String getRua() {
 return rua;
 }

public void setRua(String rua) {
 this.rua = rua;
 }
}

O código abaixo representa a classe Contato. Note que há o elemento Wrapper, para identificar que temos uma lista da classe Telefone, ou seja, pode existir mais de um telefone cadastrado nesta lista.

package br.com.tutorials.content;

import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "contato")
@XmlAccessorType(XmlAccessType.FIELD)
public class Contato {
 @XmlElement(name = "email", required = false)
 private String email;

@XmlElementWrapper(name = "telefones")
 @XmlElement(name = "telefone")
 private List<Telefone> telefones;

public String getEmail() {
 return email;
 }

public void setEmail(String email) {
 this.email = email;
 }

public List<Telefone> getTelefones() {
 return telefones;
 }

public void setTelefones(List<Telefone> telefones) {
 this.telefones = telefones;
 }
}

A classe abaixo representa a Empresa cadastrada, logo possui um conteúdo indicando para as demais classes.

package br.com.tutorials.content;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "empresa")
@XmlAccessorType(XmlAccessType.FIELD)
public class Empresa {

@XmlElement(name = "identificador", required = true)
 private String identificador;
 @XmlElement(name = "nome", required = true)
 private String nome;
 @XmlElement(name = "endereco", required = true)
 private Endereco endereco;
 @XmlElement(name = "contato", required = true)
 private Contato contato;

public String getIdentificador() {
 return identificador;
 }

public void setIdentificador(String identificador) {
 this.identificador = identificador;
 }

public String getNome() {
 return nome;
 }

public void setNome(String nome) {
 this.nome = nome;
 }

public Endereco getEndereco() {
 return endereco;
 }

public void setEndereco(Endereco endereco) {
 this.endereco = endereco;
 }

public Contato getContato() {
 return contato;
 }

public void setContato(Contato contato) {
 this.contato = contato;
 }

}

Por fim o código abaixo de teste, contém exemplos de marshal e unmarshal, com métodos simples de serem implementados.

package br.com.tutorials.content;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.StringWriter;
import java.util.ArrayList;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamResult;

public class TestMain {

 public Object createObject() {

ArrayList<Telefone> telefones = new ArrayList<Telefone>();
 Telefone tel1 = new Telefone();
 tel1.setDdd("11");
 tel1.setNum(999999999L);

Telefone tel2 = new Telefone();
 tel2.setNum(888888888L);

telefones.add(tel1);
 telefones.add(tel2);

Contato contato = new Contato();

contato.setEmail("xmlempresa@xml.com");
 contato.setTelefones(telefones);
 Endereco endereco = new Endereco();
 endereco.setCep("43238920");
 endereco.setNum("999");
 endereco.setPais("Brasil");
 endereco.setEstado("Sao Paulo");
 endereco.setCidade("Sao Paulo");
 endereco.setRua("Rua do XML");

Empresa empresa = new Empresa();
 empresa.setIdentificador("a12130");
 empresa.setNome("Empresa de teste do XML");
 empresa.setEndereco(endereco);
 empresa.setContato(contato);

return empresa;

}
 public void marshallMethod(Object object) {
 StringWriter output = new StringWriter();
 try {
 JAXBContext jaxbContext = JAXBContext
 .newInstance(object.getClass());
 Marshaller marshal = jaxbContext.createMarshaller();
 marshal.setProperty(
 javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT,
 Boolean.TRUE);
 marshal.marshal(object, new StreamResult(output));
 } catch (JAXBException e) {
 e.printStackTrace();
 }
 // Pode gerar um arquivo xml com este output tambem, basta trabalhar em cima dele
 System.out.println(output);
 }

 public Object unmarshallMethod(File location) {
 try {
 JAXBContext jaxbContext = JAXBContext.newInstance(Empresa.class);
 Unmarshaller unmarshal = jaxbContext.createUnmarshaller();
 return unmarshal.unmarshal(new FileInputStream(location));
 } catch (JAXBException e) {
 e.printStackTrace();
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 }
 return null;
 }

public static void main(String[] args) {
 TestMain test = new TestMain();
 Object object = test.createObject();
 test.marshallMethod(object);
 Empresa emp = (Empresa) test.unmarshallMethod(new File("post.xml"));
 // Sugiro adicionar um metodo toString para as classes: Contato,
 // Empresa, Endereco e Telefone ao inves de printar cada get
  System.out.println(emp.getIdentificador());
 }
}

Por hoje é só, espero que seja de grande ajuda o uso desta poderosa biblioteca para trabalhar com conteúdo XML, até a próxima.

Observações: O código continha muitos comentários, como anotações de retorno etc., porém o WordPress não aceitou, não entendi o motivo =/

Obrigado.

Referências:
JAXB Project. JAXB Tutorial. Disponível em: https://jaxb.java.net/tutorial/ (Acessado em: 22/09/2013) Está página contém de maneira descritiva inúmeros exemplos do uso da biblioteca, essencial para o aprendizado.

MongoDB modelo de dados orientado a documentos NoSQL: Introdução

Como primeiro post o tema escolhido foi o MongoDB. Por quais motivos? NoSQL (Not Only SQL) é algo citado com muita frequência hoje, principalmente envolvendo conceitos de desenvolvimento distribuído de software, big data etc.

Encontrei no MongoDB uma saída interessante ao clássico SQL (Structured Query Language). Mas como trabalha o MongoDB?

O MongoDB é um banco de dados NoSQL open-source orientado a documentos, a qual foi escrito na linguagem C++. Como entrada, recebe os dados no formato JSON (Javascript Object Notation), bastante utilizado hoje na web, principalmente em Javascript e estilos arquiteturais como REST.

Algumas características interessantes relacionadas ao MongoDB:

  • Possui suporte a processamento de dados, usufruindo do modelo de programação Map/Reduce da qual foi desenvolvido pela Google;
  • Possui armazenamento de arquivos utilizando GridFS;
  • Replicação em LANs e WANs;
  • Possui diversos drivers para trabalhar juntamente com as principais linguagens de programação hoje utilizadas no mercado ou em âmbito acadêmico: Python, Java, C, C++, C# entre outras.

Para mais informações sobre o MongoDB visite a sua página oficial: http://www.mongodb.org/

Comandos Básicos

Este post não inclui métodos de instalação da base de dados MongoDB para nenhum sistema operacional. Visite o site oficial já descrito anteriormente para obter esta informação.

Os comandos básicos e triviais para uso do MongoDB que considerei para criação deste post são:

show dbs

Este comando exibe todas as bases de dados presentes no momento.

use database

Este comando permite que a variável db (database) seja apontada para uma base de dados a ser manipulada. O conjunto de caracteres “database” deve ser alterado para o nome da base de dados a escolha do desenvolvedor, por exemplo: use meu_banco.

show collections

Após criar um apontador db para alguma base de dados, o comando show collections exibe as coleções presentes na base de dados atual. Collections são similares as tabelas em modelos relacionais, mas como descrito, o mongo trabalha pela inserção de documentos via JSON, ou seja, as coleções armazenam um conjunto de documentos.

db.your_collection.insert(object)

Este comando efetua a inserção de dados em uma coleção chamada “your_collection” (similar ao use database, o usuário cria um nome para sua coleção). Object são os dados brutos, descritos como um arquivo JSON.

db.your_collection.find(object)

O comando find basicamente recebe como parâmetro um JSON a ser buscado em sua base de dados, porém sem argumentos (db.your_collection.find()) devolve todos os documentos presentes na coleção.

db.your_collection.findOne(object)

Efetua uma busca pelo object (conteúdo JSON), retornando a primeira aparição do mesmo. Se nenhum parâmetro for passado, retorna o primeiro documento inserido presente na coleção.

db.dropDatabase()

Este comando simplesmente remove a base de dados. Obviamente todas as coleções presentes na base de dados são removidas também.

db.your_collection.update(params)

Este comando recebe parâmetros para atualizar um documento dado um critério ou key/value definido. Um exemplo para este critério é uma query ou um conjunto de características apresentadas por um documento.

db.your_collection.remove(params)

Similar ao comando anterior, porém remove um ou mais documentos, depende do critério estabelecido. Quando nenhum critério é informado (params), todos os documentos são removidos, então fique sempre atento (a) a este fato e seja cuidadoso (a).

A Figura abaixo contém o shell de interação com o MongoDB.

Shell do MongoDB em um terminal Linux.

Shell do MongoDB em um terminal Linux.

Utilizando os comandos básicos do MongoDB

Antes de prosseguirmos para a inserção de dados, busca, remoção e atualização (princípios básicos de qualquer modelo de banco de dados, seja SQL ou NoSQL), ainda existe um fato interessante a respeito do MongoDB.

O MongoDB utiliza um modelo de timestamp, ObjectID que basicamente é um BSON (Binary JSON). Mas qual a sua finalidade?

No MongoDB os documentos armazenados nas coleções recebem um campo de identificação único (_id). Este campo é similar a uma chave primária no modelo relacional. O MongoDB permite aos próprios usuários manipularem o identificador (_id), inserindo-os da sua maneira. Mas caso o usuário não queira, a própria base de dados irá gerar um identificador para o usuário.

Agora, mãos a obra. A figura abaixo contém a execução dos três primeiros comandos no shell do MongoDB executado sobre o sistema operacional Linux. Observe que existia uma base de dados chamada biblioteca e ela foi excluída após o uso do comando db.dropDatabase(), assim, como descrito, todas as coleções foram removidas juntamente com a base de dados. Utilizei novamente uma base de dados chamada de biblioteca para fins didáticos, creio que a inserção de livros, seja um exemplo muito simplista e fácil de ser compreendido.

Comandos sendo executados no Shell do MongoDB.

Comandos sendo executados no Shell do MongoDB.

A figura abaixo é um exemplo de inserção de um documento na coleção livros.

Inserção de um documento no Shell do MongoDB.

Inserção de um documento no Shell do MongoDB.

O documento contém nada mais do que um conteúdo representado na forma de JSON, como descrito anteriormente ao longo do post. O livro possui um título e um autor, sendo o modelo JSON:

{ titulo: "Java - Como Programar", autor: "Paul Deitel"}

A figura abaixo contém a inserção de mais um documento na coleção de livros, mas note que autor contém um array de autores desta vez, possibilitando a inserção de vários elementos. Um fato interessante, o MongoDB permite que o array seja trabalhado como uma FIFO (First In First Out), possibilitando que novos autores sejam adicionados ao final deste array. Mas este fato não será abordado neste post.

Inserção de um documento com campo em formato de array.

Inserção de um documento com campo em formato de array.

A figura abaixo contém uma consulta sem parâmetros para a função find(). Note que a consulta retorna um identificador “_id”, já descrito ao longo deste texto.

Execução do comando find() no shell do MongoDB.

Execução do comando find() no shell do MongoDB.

A figura abaixo contém a execução da função de consulta find com um JSON sendo passado como parâmetro. Neste caso estamos procurando o livro com o título: “Java – Como Programar”. Caso existisse mais de um livro com este nome, ele seria retornado como parâmetro. Faça você mesmo o teste, crie um documento novo, por exemplo, insira um novo livro do Deitel e efetue a busca pelos livros que o Deitel possui na sua base de dados. O comando findOne(), fica a teste do leitor também.

Execução do comando find() com um JSON passado como parâmetro.

Execução do comando find() com um JSON passado como parâmetro.

Agora vamos alterar o documento cujo autor é o Deitel. Vamos adicionar um novo campo, ano de criação do livro. Observe que utilizamos o comando $set para que seja adicionado o novo campo, executando uma busca pelo mesmo título notamos que agora existe o campo ano. Mas o campo ano estará no documento cujo um dos autores é o Cormen? Resposta: não.

Comando update no MongoDB.

Comando update no MongoDB.

Por fim, para finalizarmos este post o comando de remoção de documentos. Neste caso vamos remover apenas os documentos cujo campo ano equivale a 2010. Executando uma busca, vemos que o livro do Cormen não possui o campo ano, descrito já anteriormente.

Comando remove() no MongoDB.

Comando remove() no MongoDB.

Por este post é só. Espero que tenham gostado das funcionalidades básicas do MongoDB, este modelo orientado a documentos da 10gen possui diversas características, trabalha com busca por localização geográfica (GPS), possui um modelo de agregação pipeline  etc. Uma outra hora volto com mais funcionalidades do MongoDB.

Não deixem de conferir os links a seguir, eles completam e muito este post.

http://teachmetocode.com/screencasts/introduction-to-mongodb-part-i/

Palestra no canal Gonow sobre o MongoDB sendo usado no CartolaFC (game fantasy da Globo.com), palestra ministrada por Franklin Amorim no MongoSP 2011:

MongoDB com Python no canal Pycon apac, Mathias Stearn: 

Java e MongoDB na página do Mkyong:  Java MongoDB Tutorial

Obrigado.

Referências:

MongoDB, Inc. Agile and Scalable.  Disponível em: http://www.mongodb.org/ (Acessado em: 15/09/2013) (Esta página, por si só é uma grande referência com inúmeros exemplos)