Sunteți pe pagina 1din 16

1

Java API - Manipulando objetos JSON com a JSR


353

Fique por dentro

Este artigo ir apresentar a JSR 353, Java API for JSON Processing, que viabiliza e padroniza a criao e
leitura de objetos JSON em Java. Veremos no artigo os dois modelos de leitura e gerao de contedo
JSON, conhecidos como modelo de objetos e modelo de streaming.
Ao final do artigo criaremos uma aplicao standalone utilizando a JSR como exemplo prtico. Com esta
nova API o desenvolvedor poder, rapidamente, produzir e consumir dados em JSON.
Sistemas de computadores geralmente no funcionam sozinhos, mas sim se integrando a outros sistemas, ora
provendo, ora consumindo dados. Deste modo, os recursos envolvidos para viabilizar essa comunicao,
como protocolo, APIs, formato de dados, etc. devem ser analisados quando projetamos qualquer aplicao.
Diante de tudo isso, vlido lembrar que, dependendo da soluo, podemos aumentar ou reduzir a
complexidade dessa interao.
Na plataforma Java EE muito comum o uso do RMI, que a base do EJB, para interoperabilidade entre
componentes de uma mesma aplicao. Mas esse tipo de protocolo binrio acaba sendo ineficiente como
camada de integrao entre softwares distintos, pois cria um acoplamento muito forte entre eles (devido
necessidade de exportar interfaces de servios e DTOs ver BOX 1 para a aplicao cliente), alm de
permitir a integrao apenas entre softwares que usam esta tecnologia.
BOX 1. Data Transfer Object
DTO, sigla para Data Transfer Object, representa os objetos utilizados para transferir informaes entre
camadas da aplicao, ou entre aplicaes distintas.
J os protocolos baseados em texto, como o HTTP, permitem que criemos aplicaes em qualquer
tecnologia/linguagem para servir ou consumir servios, alm de deixar a comunicao mais compreensvel
para humanos, tornando mais fcil a depurao da troca de mensagens.
Com este cenrio, os servios web, apoiados no HTTP, vm se consolidando como opo para integrao de
aplicaes.
At pouco tempo, o formato XML, aliado ao protocolo SOAP, era predominante no desenvolvimento de
web services. O SOAP uma excelente soluo de integrao, sendo um protocolo muito bem definido e
consolidado. Porm, muitas vezes o excesso de padronizao visto como um obstculo, pois faz com que a
implementao seja mais trabalhosa.
muito comum nos depararmos com problemas simples, e para solucion-los tambm comum estarmos
dispostos a abrir mo de tanta padronizao em benefcio da agilidade. neste ponto que servios REST
brilham, principalmente usando mensagens no formato JSON.
Nos ltimos anos, a notao JSON vem se consolidando na preferncia dos desenvolvedores como o
formato ideal para se trabalhar com web services. At a verso 6 da plataforma Java EE, no entanto, o Java
no contava com uma API padro para o processamento de JSON.
2

Deste modo, cada projeto utilizava uma implementao prpria ou algumas conhecidas no mercado, como
o caso do Jackson. A JSR 353 vem para preencher esta lacuna, embarcando nos containers Java EE uma
implementao padronizada para criao e leitura de contedo JSON.
Este artigo ir apresentar ao leitor a JSR 353 e como us-la para ler e gerar contedos JSON atravs de duas
tcnicas conhecidas como modelo de objetos e modelo de streaming. Depois de apresentar a API, iremos
construir um projeto de consulta de informaes climticas usando um servio web pblico que retorna
JSON, como um caso de uso prtico da API.
JavaScript Object Notation JSON
JSON vem sendo largamente adotado principalmente no desenvolvimento de servios web. Grande parte
deste crescimento se d pela flexibilidade do formato e tambm pela facilidade de leitura por humanos. Ao
contrrio do XML, JSON muito menos verboso, pois no possui o sistema de tags, mais limpo e mais
intuitivo.
Uma informao no formato JSON pode ser apresentada de duas maneiras: como um objeto simples ou
como uma lista (array). Um objeto uma sequncia de pares chave/valor, semelhante a um mapa, sempre
envolvida por chaves ({}). Na estrutura do par chave/valor, a chave sempre uma String e o valor pode ser
de seis tipos: uma String, um nmero (inteiro ou decimal), outro objeto, um array, true, false ou null.
Cada chave separada do valor por dois pontos e os conjuntos chave/valor so separados entre si por
vrgulas. Como o valor pode ser outro objeto, possvel formar uma estrutura hierrquica usando JSON.
Diferentemente do objeto, o array envolvido por colchetes ([]) e seus elementos so separados por vrgula.
Tais elementos no precisam ter a mesma estrutura ou ser do mesmo tipo.
Em consequncia disso, podemos ter um array cujo primeiro elemento um objeto JSON e o segundo
elemento pode ser outro array. A Listagem 1 mostra um objeto JSON vlido que contempla as
possibilidades descritas.
Listagem 1. Exemplo de objeto JSON vlido.
{
"editora" : "DevMedia",
"ano" : 2021,
"revista" : "Java Magazine",
"edicao" : 200,
"artigos" : [
{
"titulo" : "JEE21 Criando um EJB com uma linha de cdigo",
"caracteres" : 23000,
"revisado" : true,
"data" : "21/08/2021"
},
{
"titulo" : "JBrain Programming Java com comando cerebral",
"caracteres" : 25000,
"revisado" : false,
"data" : null
}
],
"tiragem" : 120000
}
JSR 353
3

De acordo com a especificao, a Java EE 7 prov uma API para analisar, transformar e fazer consultas a
dados JSON usando um modelo de objetos ou um modelo de streaming. Na prtica isso significa que a API
nos oferece dois modelos para trabalhar com JSON, a saber:
O modelo de objeto: Neste modelo, tanto na leitura quanto na criao de um objeto JSON a API cria um
objeto em memria, permitindo a leitura de seus dados e tambm a manipulao, como a alterao de
valores ou a insero de novos valores na estrutura.
Este modelo consome mais memria que o modelo de streaming, pois exige que o objeto seja carregado de
uma vez para a memria;
O modelo de streaming: Neste modelo a API disponibiliza um parser baseado em eventos para a leitura
de objetos JSON. Durante o processamento do objeto, eventos do tipo iniciou um array, terminou um
array, inicio um objeto, entre outros, permitem que desenvolvedores tratem apenas os blocos de dados
que lhes interessem, descartando o restante. Devido a esta caracterstica, um modelo mais econmico para
a memria, sendo indicado para grandes volumes de dados (ou para mquinas com pouca memria).
A especificao define um conjunto de interfaces e classes nos pacotes javax.json e javax.json.stream que
o desenvolvedor precisa utilizar para construir ou ler objetos no formato JSON. Veremos agora esses
principais elementos com uma breve explicao de sua utilizao. Mais adiante veremos essas
classes/interfaces em ao, lendo e gerando dados JSON.
Json: Esta classe uma fbrica para criar objetos para processar JSON. Atravs dela obtemos objetos para
criao e leitura de documentos JSON, tanto no modelo de objetos quanto no modelo de streaming;
JsonArrayBuilder: Esta interface representa um builder de arrays JSON;
JsonObjectBuilder: Esta interface representa um builder de objetos JSON;
JsonStructure: Esta a superinterface dos tipos JsonArray e JsonObject;
JsonArray: Esta interface representa um array imutvel de JSON. O item artigos da Listagem 1, por
exemplo, quando lido pela API, transformado em um JsonArray;
JsonObject: Esta interface representa um objeto JSON. Cada item da lista de artigos da Listagem 1, por
exemplo, quando lido pela API, transformado em um JsonObject;
JsonReader: Esta interface possibilita a leitura de um objeto ou array JSON a partir de uma determinada
fonte;
JsonGenerator: Esta interface possibilita a gerao de objetos JSON para um stream de sada;
JsonParser: Esta interface prov um mecanismo de leitura de JSON a partir de um stream.
Trabalhando com o Modelo de Objeto
Para criar um objeto JSON usando o modelo de objeto, devemos instanciar um objeto do tipo
javax.json.JsonObjectBuilder, ou do tipo javax.json.JsonArrayBuilder para criar um array.
De acordo com a especificao, estes objetos devem ser criados por objetos builders (Builder Pattern) que
so definidos pela API. Para obter os builders, usamos os mtodos estticos createObjectBuilder() ou
createArrayBuilder() da classe Json.
4

Com o builder em mos podemos utilizar o mtodo add() sucessivamente para adicionar elementos ao
objeto ou ao array e finalizar a construo usando o mtodo build(), que retorna um JsonObject ou um
JsonArray (ambos so subclasses de JsonStructure).
Os exemplos de cdigo desta seo so para demonstrar o funcionamento da API. Todo o cdigo est
disponvel no site da revista e foi desenvolvido usando o Maven para controlar as dependncias do projeto e
realizar o build.
Mais adiante, como j informado, iremos expor a criao de um projeto usando a API e como adicionar as
dependncias para conseguir executar uma aplicao standalone com tal recurso.
A Listagem 2 mostra a criao de um objeto JSON usando o modelo de objeto.
Listagem 2. Criando um objeto JSON usando o modelo de objeto.
JsonObjectBuilder builder = Json.createObjectBuilder();

builder.add("titulo", "Curtindo a Vida Adoidado");
builder.add("ano", 1986);
builder.add("diretor", "John Hughes");
builder.add("genero", "Comdia");
builder.add("oscar", false);

JsonObject json = builder.build();

System.out.println(json);
Quando executado, um programa com o cdigo da Listagem 2 apresenta o seguinte resultado:
{"titulo":"Curtindo a Vida Adoidado", "ano":1986, "diretor":"John Hughes", "genero":"Comedia",
"oscar":false}
Como explicado anteriormente, o builder JsonObjectBuilder constri objetos e o builder
JsonArrayBuilder constri arrays. A Listagem 3 mostra a criao de um array JSON usando o modelo de
objeto.
Listagem 3. Criando um array JSON usando o modelo de objeto.
JsonArrayBuilder builder = Json.createArrayBuilder();

builder.add("Java");
builder.add(true);
builder.add(8176);
builder.addNull();
builder.add(12.33);

JsonArray json = builder.build();

System.out.println(json);
O resultado da execuo desse cdigo :
["Java",true,8176,null,12.33]
Como o leitor deve ter reparado, existem vrios mtodos add() sobrecarregados, tanto na classe
JsonObjectBuilder quanto na classe JsonArrayBuilder. A invocao de cada um depende dos parmetros
informados. A Listagem 4 exibe a lista de mtodos add() com seus respectivos parmetros e retornos.
5

Listagem 4. Mtodos add() de JsonObjectBuilder e JsonArrayBuilder.
JsonObjectBuilder add(String name, BigDecimal value)
JsonObjectBuilder add(String name, BigInteger value)
JsonObjectBuilder add(String name, boolean value)
JsonObjectBuilder add(String name, double value)
JsonObjectBuilder add(String name, int value)
JsonObjectBuilder add(String name, JsonArrayBuilder builder)
JsonObjectBuilder add(String name, JsonObjectBuilder builder)
JsonObjectBuilder add(String name, JsonValue value)
JsonObjectBuilder add(String name, long value)
JsonObjectBuilder add(String name, String value)
JsonObjectBuilder addNull(String name)

JsonArrayBuilder add(BigDecimal value)
JsonArrayBuilder add(BigInteger value)
JsonArrayBuilder add(boolean value)
JsonArrayBuilder add(double value)
JsonArrayBuilder add(int value)
JsonArrayBuilder add(JsonArrayBuilder builder)
JsonArrayBuilder add(JsonObjectBuilder builder)
JsonArrayBuilder add(JsonValue value)
JsonArrayBuilder add(long value)
JsonArrayBuilder add(String value)
JsonArrayBuilder addNull()
Na construo de um objeto ou de um array JSON, devemos chamar sucessivamente o mtodo add() do
objeto builder para adicionar novos elementos. Toda chamada de add() retorna o prprio builder utilizado na
invocao do mtodo.
Esta caracterstica chamada de interface fluente, cujo uso reduz sensivelmente a quantidade de cdigo e
facilita a leitura. A Listagem 5 mostra como fica o exemplo da Listagem 3 usando interface fluente.
Listagem 5. Criando um objeto JSON usando o modelo de objeto e interface fluente.
JsonObject json = Json.createObjectBuilder()
.add("titulo", "Curtindo a Vida Adoidado")
.add("ano", 1986)
.add("diretor", "John Hughes")
.add("genero", "Comedia")
.add("oscar", false)
.build();

System.out.println(json);
Podemos tambm combinar builders de objetos e de arrays para criar objetos com valores do tipo array ou
arrays com elementos do tipo objeto, pois a API permite o aninhamento de objetos e arrays. Este tipo de
situao pode ser til em casos como o exposto na Listagem 1, no qual temos um objeto na raiz com
informaes de uma revista, sendo que uma das chaves, artigos, remete a um array e cada item deste array
ainda outro objeto. A Listagem 6 mostra como fazer o aninhamento.
Listagem 6. Aninhando objetos e arrays em uma estrutura JSON.
JsonObject json = Json.createObjectBuilder()
.add("titulo", "Curtindo a Vida Adoidado")
.add("ano", 1986)
.add("diretor", Json.createObjectBuilder().add("nome", "John hughes").add("pais",
"EUA"))
.add("genero", Json.createArrayBuilder().add("comedia").add("aventura"))
.add("oscar", false)
6

.build();

System.out.println(json);
O resultado da execuo do cdigo da Listagem 6 :
{"titulo":"Curtindo a Vida Adoidado", "ano":1986, "diretor":{"nome":"John hughes", "pais":"EUA"},
"genero":["comedia", "aventura"], "oscar":false}
Usando o Modelo de Objeto para leitura de dados
Anteriormente vimos como criar objetos ou arrays JSON usando a especificao atravs dos objetos
builders. Alm de criar objetos, a API tambm prov formas de leitura de dados no formato JSON. Para isso,
dispomos do objeto JsonReader.
Para obter um JsonReader, usamos o mtodo esttico createReader() da classe Json. Este mtodo recebe
como parmetro qualquer implementao de reader (da API java.io.Reader), como FileReader,
BufferedReader, etc., e retorna um JsonReader.
A Listagem 7 mostra como realizar a leitura de um JSON usando a API e considerando que o arquivo
json.txt tenha o contedo da Listagem 1.
Listagem 7. Leitura do contedo JSON de um arquivo usando o modelo de objeto.
JsonReader reader = Json.createReader(new FileReader("/tmp/json.txt"));

JsonObject json = reader.readObject();

String revista = json.getString("revista");
int ano = json.getInt("ano");
JsonArray artigos = json.getJsonArray("artigos");

JsonObject primeiroArtigo = (JsonObject) artigos.get(0);
String titulo = primeiroArtigo.getString("titulo");

System.out.println("Revista: " + revista);
System.out.println("Ano: " + ano);
System.out.println("Primeiro artigo: " + titulo);
importante complementar que a interface JsonReader disponibiliza trs mtodos: 1) readObject()
usado no exemplo assume que a raiz do contedo a ser lido um objeto e retorna um JsonObject; 2)
readArray() assume que a raiz um array e retorna um JsonArray; e, 3) read(), que genrico e retorna
um JsonStructure (superclasse de JsonObject e JsonArray) para situaes em que no sabemos o tipo do
contedo e devemos trat-lo no cdigo.
Com o objeto do tipo JsonObject em mos podemos fazer as leituras como se estivssemos com um Mapa
de objetos (e estamos, pois JsonObject implementa Map), com a diferena que devemos invocar o mtodo
getter de acordo com o tipo esperado do valor a ser retornado. Por exemplo, se usarmos getString(nome)
porque sabemos que a chave nome ir retornar um valor do tipo String (contedo do nome), mas se
usarmos getInt(idade) porque sabemos que a chave idade ir retornar um valor do tipo inteiro.
Outro ponto que podemos verificar na Listagem 7 que na leitura do atributo artigos invocamos
getJsonArray(), que retorna um JsonArray. Diferente de JsonObject, trabalhar com JsonArray
equivalente a trabalhar com uma collection, visto que JsonArray implementa a interface Collection. Sendo
assim, podemos usar o mtodo get(index) para buscar um elemento do JsonArray.
7

Usando o Modelo de Streaming para leitura de dados
Como explicado no incio do artigo, o modelo de streaming indicado quando temos grandes volumes de
dados de entrada, mas s nos interessa algumas partes desses dados. Ao contrrio do modelo de objeto que
carrega toda a estrutura do JSON lido em memria para que naveguemos pela rvore, o modelo de streaming
oferece uma interface de eventos para que possamos filtrar os contedos que nos interessam.
Para usarmos o modelo de streaming invocamos o mtodo esttico createParser() da classe Json. Este
mtodo recebe como parmetro qualquer implementao de InputStream e retorna um objeto do tipo
JsonParser que se comporta como um iterator. Com o parser, invocamos o mtodo hasNext() como
condio de um lao e o next() para ler o prximo evento. A Listagem 8 implementa esta leitura e imprime
o objeto event em cada iterao.
Listagem 8. Leitura do contedo JSON de um arquivo usando o modelo de streaming
JsonParser parser = Json.createParser(new FileInputStream("/tmp/json.txt"));

while (parser.hasNext()) {
JsonParser.Event event = parser.next();
System.out.println(event);
}
Considerando que o arquivo /tmp/json.txt tenha o contedo do exemplo da Listagem 1, a sada do cdigo
apresentado deve ser idntica exibida na Listagem 9. direita de cada evento foi adicionada uma
explicao do que est sendo iterado.
Listagem 9. Resultado da leitura do JSON usando o modelo de streaming.
START_OBJECT Encontrou o { no incio do arquivo, que caracteriza o incio de um
objeto
KEY_NAME Encontrou a chave editora
VALUE_STRING Encontrou o valor Devmedia do tipo STRING
KEY_NAME Encontrou a chave ano
VALUE_NUMBER Encontrou o valor 2021 do tipo NUMBER
KEY_NAME Encontrou a chave revista
VALUE_STRING Encontrou o valor Java Magazine do tipo STRING
KEY_NAME Encontrou a chave edicao
VALUE_NUMBER Encontrou o valor 200 do tipo NUMBER
KEY_NAME Encontrou a chave artigos
START_ARRAY Encontrou o incio do array de artigos
START_OBJECT Encontrou o incio do objeto artigo
KEY_NAME Encontrou a chave titulo
VALUE_STRING Encontrou o valor JEE21 Criando... do tipo STRING
KEY_NAME Encontrou a chave caracteres
VALUE_NUMBER Encontrou o valor 23000 do tipo NUMBER
KEY_NAME Encontrou a chave revisado
VALUE_TRUE Encontrou o valor do tipo TRUE
KEY_NAME Encontrou a chave data
VALUE_STRING Encontrou o valor 21/08/2021 do tipo STRING
END_OBJECT Encontrou o fim do objeto artigo
.
.
.
END_ARRAY Encontrou o fim do array de artigos
KEY_NAME Encontrou a chave tiragem
VALUE_NUMBER Encontrou o valor 12000 do tipo NUMBER
END_OBJECT Encontrou o fim do objeto }
8

A execuo do cdigo da listagem deve exibir apenas os tipos de evento. Por exemplo, KEY_NAME
quando encontrou uma chave, ou VALUE_STRING quando encontrou um valor do tipo String. Nesse
momento vale lembrar que um dado em JSON no nada mais do que uma sucesso de chaves e valores.
Com esse tipo de informao o desenvolvedor consegue filtrar apenas os valores que lhe interessa. Para
obter o valor, devemos usar os mtodos get do prprio objeto JsonParser. Estes mtodos so responsveis
por recuperar o valor do objeto encontrado, seja ele uma chave (que sempre ser do tipo String) ou o valor
de uma chave, que tem um getter para cada tipo.
A Listagem 10 mostra um exemplo de leitura de um arquivo JSON usando o modelo de streaming que
carrega e exibe os nomes de todas as chaves (primeiro if), valores do tipo String (tambm no primeiro if) e
valores do tipo Number (segundo if). A condicional para capturar nomes de chaves e valores do tipo String
est agrupada porque ambos usam o mesmo getter para recuperar o valor (getString()). No faria sentido em
uma aplicao real este tipo de abordagem, mas aqui estamos usando-a apenas como exemplo da sintaxe.
Listagem 10. Lendo valores usando o modelo de streaming
JsonParser parser = Json.createParser(new FileInputStream("/tmp/json.txt"));

while (parser.hasNext()) {
JsonParser.Event event = parser.next();
if (event == Event.KEY_NAME || event == Event.VALUE_STRING) {
System.out.println(parser.getString());
}
if (event == Event.VALUE_NUMBER) {
System.out.println(parser.getLong());
}
}
Repare que invocamos o getString() do parser para chaves e valores String, e o getLong() para valores
numricos.
Em uma situao mais real, consideremos que o sistema deva ler apenas os nomes dos artigos, desprezando
todo o resto. Para isto, devemos tratar apenas a leitura de valores para chaves de nome titulo. A Listagem
11 mostra como implementar este tipo de soluo.
Listagem 11. Filtrando o contedo usando o modelo de streaming.
JsonParser parser = Json.createParser(new FileInputStream("/tmp/json.txt"));

while (parser.hasNext()) {
JsonParser.Event event = parser.next();
if (event == Event.KEY_NAME && parser.getString().equals("titulo")) {
parser.next();
System.out.println(parser.getString());
}
}
Neste exemplo nos preocupamos apenas com os eventos que nos interessa para recuperar apenas uma parte
da informao; no caso, o ttulo de cada artigo. Este tipo de soluo faz sentido em situaes nas quais
possumos um grande volume de dados a ser lido, mas somente uma parte da informao necessria.
Por exemplo, se nossa aplicao estiver rodando em uma PaaS (Plataforma como Servio), pode ser crucial
usar o modelo de streaming para reduzir o custo do servio, visto que este, muitas vezes, cobra por dados
trafegados.
Produzindo JSON com o Modelo de Streaming
9

Assim como no modelo de objetos, tambm possvel gerar uma estrutura JSON usando o modelo de
streaming. Para isso, devemos obter um objeto da classe JsonGenerator atravs do mtodo esttico
createGenerator() da classe Json. Aps criar o objeto devemos usar os mtodos write() para a escrita no
stream.
No modelo de streaming, sempre iniciamos a gerao do JSON com o mtodo writeStartArray() (para um
JSON com um array na raiz) ou writeStartObject() (para um JSON com um objeto na raiz). Para adicionar
elementos estrutura usamos o mtodo write() com os parmetros chave e valor ou write() com apenas o
parmetro valor para itens de um array. A Listagem 12 mostra como escrever um JSON usando o modelo
de streaming.
Listagem 12. Escrevendo um JSON usando o modelo de streaming.
JsonGenerator gen = Json.createGenerator(new FileOutputStream("/tmp/json_out.txt"));

gen.writeStartObject()
.write("nome", "Joao")
.write("idade", 20)
.write("profissao", "Programador")
.writeStartArray("linguagens")
.write("Java")
.write("Scala")
.write("Javascript")
.write("C++")
.write("Ruby")
.writeEnd()
.writeEnd()
.close();
O cdigo foi propositalmente identado para facilitar a leitura e a compreenso do objeto criado. Se
verificarmos o contedo do arquivo gerado pelo cdigo anterior, devemos encontrar o contedo da
Listagem 13.
Listagem 13. Sada do programa da Listagem 12.
{
"nome":"Joao",
"idade":20,
"profissao":"Programador",
"linguagens":[
"Java",
"Scala",
"Javascript",
"C++",
"Ruby"
]
}
Consulta do Clima com a API de JSON-P
Agora que o leitor j se familiarizou com a API para JSON da JSR 353, vamos criar uma aplicao que
utiliza servios web baseados em JSON para consultar uma base de dados pblica de informaes climticas
e apresentar ao usurio a temperatura, condies do cu e umidade de uma cidade escolhida atravs de uma
interface grfica.
importante ressaltar que todo container ter uma implementao da JSR embarcada, pois ela faz parte da
Java EE 7. No entanto, em uma aplicao standalone necessrio importar a implementao de referncia
para o classpath, como veremos adiante.
10

Alm da implementao de referncia da JSR 353, usaremos Swing para construir a interface grfica.
Para iniciar o desenvolvimento da aplicao, o leitor deve criar um diretrio para hospedar o cdigo. Como
o projeto usar o Maven para gesto de dependncias e build, devemos criar um arquivo nomeado pom.xml
na raiz do diretrio criado. O contedo do pom.xml apresentado na Listagem 14.
Listagem 14. Arquivo pom da aplicao de clima.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.devmedia.jsr353</groupId>
<artifactId>clima</artifactId>
<version>1.0.0</version>

<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>

<mainClass>com.devmedia.jsr353.clima.main.ClimaFrame</mainClass>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

<dependencies>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.0.4.Final</version>
</dependency>
</dependencies>

</project>
Observando atentamente esse arquivo, notamos que existem dois plugins informados na tag
pluginManagement. O primeiro, maven-compiler-plugin, para configurar o compilador do Maven para
usar o Java 7.
11

O segundo, exec-maven-plugin, nos permite executar a aplicao atravs de um comando Maven. Para isto,
temos que configurar esse plugin informando a classe com.devmedia.jsr353.clima.main.ClimaFrame
como ponto de incio, pois alm desta ser responsvel por renderizar uma janela, por questo de
simplicidade tambm a usaremos para iniciar a aplicao, por isso ela ir conter o mtodo esttico main().
A vantagem de executar a aplicao usando o Maven no ter que informar manualmente as dependncias
no classpath, como faramos no caso de executar a aplicao diretamente pelo comando java. Alm disso, o
Maven tambm resolve as dependncias transitivas, ou seja, as dependncias das dependncias.
Logo abaixo no XML esto as dependncias. A primeira, javax.json, a implementao de referncia da
JSR 353. Depois temos a javax.ws.rs-api e a resteasy-client, que so, respectivamente, a API e a
implementao de outra JSR para facilitar a criao de clientes de servios REST.
Feitas as configuraes iniciais do projeto, devemos comear a desenvolver o cdigo que ir consumir o
servio pblico de informaes climticas. Para atender este requisito, criaremos uma classe chamada
ClimaService. Nesta classe teremos um mtodo chamado getClima() que receber como parmetro a
cidade a ser consultada.
O mtodo far uma chamada REST a um servio pblico e retornar um JSON com informaes climticas.
Com a API de JSON-P iremos ler os dados retornados pelo servio e construir um objeto ClimaInfo com
informaes de temperatura, umidade, nome da cidade encontrada e condies do cu.
Para apresentar os dados ao usurio utilizaremos um JFrame chamado ClimaFrame com componentes
como o JTextField, para ser o ponto de entrada dos dados, e JLabels, para exibir os resultados.
Na Listagem 15 possvel analisar a implementao da classe ClimaService. Como um projeto Maven,
crie o arquivo ClimaService.java dentro da pasta src/main/java a partir da raiz do projeto.
Listagem 15. Cdigo da classe ClimaService.
public class ClimaService {

public ClimaInfo getClima(String cidade) {

Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target
("http://www.previsaodotempo.org/api.php").queryParam("city", cidade);
Response response = target.request().get();
String clima = response.readEntity(String.class);

System.out.println(clima);
JsonReader reader = Json.createReader(new StringReader(clima));
JsonObject obj = reader.readObject();
JsonObject data = obj.getJsonObject("data");

if (data.containsKey("error") == false) {
String location = data.getString("location");
String temp = data.getString("temperature");
String humidity = data.getString("humidity");
String skytext = data.getString("skytext");
ClimaInfo info = new ClimaInfo();
info.cidade = location;
info.temperatura = String.format("%.1f", ((Long.valueOf(temp) -
32) / 1.8));
info.umidade = humidity;
info.nuvem = skytext.toUpperCase().contains("CLOUD");
return info;
} else {
12

return null;
}
}
}
Como pode ser verificado, no incio do mtodo getClima() estamos fazendo uma chamada para um servio
web pblico. Para isso usamos classes como Client, WebTarget e Response, que fazem parte da nova API
para clientes REST.
No est no escopo deste artigo detalhar o uso desta API; basta o leitor entender que este cdigo nos abstrai
de vrios detalhes de conexes e requisies com o protocolo HTTP e nos retorna um JSON na varivel
clima. Para mais informaes sobre REST 2.0, leia o artigo publicado na Java Magazine 122.
Apenas para depurao, o mtodo imprime na sada padro o valor bruto do JSON e inicia o processo de
converso utilizando um StringReader. Como esse servio retorna um objeto na raiz, o primeiro objeto
extrado um JsonObject. A partir da raiz extramos o objeto data, que tambm um JsonObject.
Na sequncia verificamos se o objeto data contm o atributo error, utilizando o mtodo containsKey() da
API. Caso identifique a presena deste atributo, o servio retorna null.
Caso contrrio, inicia a leitura dos atributos do objeto, como cidade, temperatura, umidade e condies do
cu e os converte para um objeto do tipo ClimaInfo, descrito na Listagem 16.
Note que na converso estamos transformando a temperatura de Fahrenheit para Celsius e convertendo as
condies de cu em um booleano apenas para informar se existem nuvens ou no (poderamos ser mais
detalhistas neste ponto).
Listagem 16. Implementao da classe ClimaInfo.
public class ClimaInfo {

public String cidade;
public String temperatura;
public String umidade;
public boolean nuvem;

}
Para construir a tela que receber a entrada dos dados e apresentar os resultados, vamos utilizar um
JFrame. A classe ClimaFrame est descrita na Listagem 17.
Listagem 17. Implementao de ClimaFrame.
public class ClimaFrame extends JFrame {

public ClimaFrame() {

super("JClima");
setSize(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
getContentPane().setBackground(Color.white);
getContentPane().setLayout(null);

final JTextField textCity = new JTextField();
textCity.setLocation(30, 30);
textCity.setSize(340, 50);
textCity.setFont(new Font("Arial", Font.PLAIN, 24));
13

getContentPane().add(textCity);

final JLabel labelTemp = new JLabel();
labelTemp.setLocation(30, 60);
labelTemp.setSize(340, 250);
labelTemp.setFont(new Font("Arial", Font.PLAIN, 100));
getContentPane().add(labelTemp);

/* Apenas parte do cdigo de construo do ClimaFrame exibido nesta
listagem.
O cdigo completo da aplicao, com os detalhes de construo do frame e de
seus
componentes, est disponvel no site da revista. */

final ClimaService climaService = new ClimaService();

textCity.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent e) {
if (e.getKeyChar() == KeyEvent.VK_ENTER) {
String city = ((JTextField)
e.getSource()).getText();
ClimaInfo info = climaService.getClima(city);
if (info == null) {
labelTemp.setText("");
labelCity.setText("Cidade no encontrada.");
labelHumidity.setText("");
labelSun.setVisible(false);
labelCloud.setVisible(false);
}
else {
labelTemp.setText(info.temperatura + "
\u00b0C");
labelCity.setText(info.cidade);
labelHumidity.setText("Umidade: " +
info.umidade + "%");
labelSun.setVisible(info.nuvem == false);
labelCloud.setVisible(info.nuvem);
}
}
}
});

setVisible(true);
}

public static void main(String[] args) {
new ClimaFrame();
}
}
Como o leitor deve ter reparado, o cdigo da classe que implementa a janela da aplicao utiliza dois
arquivos de imagem, sol.png e nuvem.png. Estas imagens sero exibidas dentro de JLabels dependendo do
retorno do servio. A estrutura de diretrios do nosso projeto exemplo deve ficar semelhante Figura 1.
14


Figura 1. Estrutura do projeto Clima.
Os arquivos com as imagens, assim como os cdigos, podem ser baixados no site da revista. Depois de criar
as classes e inserir os arquivos com as imagens no projeto, podemos compil-lo e execut-lo usando os
comandos do Maven. A Listagem 18 mostra como fazer isso.
Listagem 18. Compilando e executando a aplicao.
$ mvn clean install
.
.
.
$ mvn exec:java
Aps a execuo do comando mvn clean install o Maven ir exibir no console uma srie de informaes
referentes ao download das dependncias e tambm detalhes do processo de build. Estes logs no foram
apresentados na listagem por questes de espao.
Concludo o build com sucesso, o comando mvn exec:java utiliza um plugin do Maven para executar a
aplicao, iniciando pela classe configurada no pom.xm,l conforme descrito anteriormente.
A janela construda com a classe ClimaFrame ser exibida na tela contendo uma caixa de texto que
permitir ao usurio informar o nome de uma cidade e pressionar Enter para realizar a busca dos dados.
Feito isso, a consulta ao servio ser realizada, os dados sero lidos usando a API de JSON-P e os resultados
sero apresentados, conforme a Figura 2.
15


Figura 2. Tela da aplicao sendo executada.
Alm de apresentar os dados climticos na tela, a aplicao tambm imprimiu no console o valor bruto do
JSON recebido pelo servio. Este resultado exposto na Listagem 19.
Listagem 19. Retorno dos dados em JSON do servio de consulta do clima.
{"apiVersion":"1.0", "data":{ "location":"Rio de Janeiro, BRA",
"temperature":"82", "skytext":"Clear",
"humidity":"55", "wind":"10",
"date":"2014-03-15", "day":"Monday" }
}
Com o crescimento do uso de web services REST que produzem e consomem dados no formato JSON, a
JSR 353 preencheu uma importante lacuna da Java EE referente ao processamento desse tipo de dado.
Essa especificao foi elaborada pensando em duas formas distintas de uso, o modelo de objetos e o modelo
de streaming. O modelo de objetos til quando temos um volume pequeno de dados para ser lido ou
gerado, pois tanto na leitura quando na gerao os objetos so inteiramente carregados na memria.
O modelo de streaming, por sua vez, atende grandes volumes de dados evitando grandes alocaes de
memria, porm torna o desenvolvimento um pouco menos simples do que o modelo de objetos.
Agora que o processamento de dados do tipo JSON est previsto em especificao, passa a ser um item a
menos que o desenvolvedor deve se preocupar caso opte por alterar o container em que a sua aplicao ser
executada.
Alm disso, vale ressaltar que o ganho no est somente na portabilidade, pois agora o desenvolvedor
tambm no precisa mais implementar um parser ou importar um parser de terceiros, reduzindo assim a
complexidade da prpria aplicao.
16

Links
Pgina do IETF que define o padro JSON
http://tools.ietf.org/html/rfc4627
Pgina da documentao da API
http://docs.oracle.com/javaee/7/api/javax/json/package-summary.html
Pgina da JSR 353: Java API for JSON Processing.
http://jcp.org/en/jsr/detail?id=353
API pblica para obter informaes sobre a previso do tempo.
http://www.previsaodotempo.org

S-ar putea să vă placă și