sábado, 9 de junho de 2012

Consumindo Web Services REST

Se você precisa consumir Web Services REST que utilizam JSON na requisição e na resposta, abaixo tem um exemplo de classe completa em Java que realiza GETs e POSTs em um determinado serviço. Também utilizei os métodos de transformação em JSON que mostrei em outro post.

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.MappingJsonFactory;
import org.codehaus.jackson.map.ObjectMapper;

public class ClientWS {

   public static Object getObjeto(Class tipoObjetoRetorno, String urlWebService, String... parametros) {
      Object objetoRetorno = null;
	
      try {
         for(String parametro: parametros){
            urlWebService = urlWebService + "/" + parametro.replaceAll(" ", "%20");
         }
		
         URL url = new URL(urlWebService);
         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
         connection.setRequestMethod("GET");
         connection.setConnectTimeout(15000);
         connection.setRequestProperty("login", "teste");
         connection.setRequestProperty("senha", "teste");
         connection.connect();

         String responseJson = inputStreamToString(connection.getInputStream());
         connection.disconnect();
		
         return fromJson(responseJson, tipoObjetoRetorno);

      } catch (Exception e) {
         e.printStackTrace();
      }	
      return objetoRetorno;
   }

   public static Object postObjeto(Object objetoEnvio, Class tipoObjetoRetorno, String urlWebService) {
      Object objetoRetorno = null;
	
      try {
         String requestJson = toJson(objetoEnvio);
		
         URL url = new URL(urlWebService);
         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
         connection.setRequestMethod("POST");
         connection.setDoOutput(true);
         connection.setUseCaches(false);
	 connection.setConnectTimeout(15000);
         connection.setRequestProperty("login", "teste");
         connection.setRequestProperty("senha", "teste");
         connection.setRequestProperty("Content-Type", "application/json");
         connection.setRequestProperty("Accept", "application/json");
         connection.setRequestProperty("Content-Length", Integer.toString(requestJson.length()));
			
         DataOutputStream stream = new DataOutputStream(connection.getOutputStream());
         stream.write(requestJson.getBytes("UTF-8"));
         stream.flush();
         stream.close();
         connection.connect();

         String responseJson = inputStreamToString(connection.getInputStream());
         connection.disconnect();
         objetoRetorno = fromJson(responseJson, tipoObjetoRetorno);

      } catch (Exception e) {
         e.printStackTrace();
      }
      return objetoRetorno;
   }


   public static String inputStreamToString(InputStream is) throws IOException {
      if (is != null) {
         Writer writer = new StringWriter();

         char[] buffer = new char[1024];
         try {
            Reader reader = new BufferedReader(new InputStreamReader(is,"UTF-8"));
            int n;
            while ((n = reader.read(buffer)) != -1) {
               writer.write(buffer, 0, n);
            }
         } finally {
            is.close();
         }
         return writer.toString();
      } else {
         return "";
      }
   }

   public static String toJson(Object objeto) throws Exception {
      ObjectMapper mapper = new ObjectMapper();
      StringWriter jsonValue = new StringWriter();
      mapper.writeValue(new PrintWriter(jsonValue), objeto);
      return jsonValue.toString();
   }


   public static Object fromJson(String json, Class objectClass) throws Exception {
      JsonFactory f = new MappingJsonFactory();
      JsonParser jp = f.createJsonParser(json);
      Object obj = jp.readValueAs(objectClass);
      return obj;
   }

}


Manipulação de Strings

Uma forma fácil de formatar strings em java é utilizando a classe MaskFormatter.

import javax.swing.text.MaskFormatter;

public static String formatarString(String texto, String mascara) {
    if(texto == null){
        return null;
    }
    try {
        MaskFormatter mf = new MaskFormatter(mascara);
        mf.setValueContainsLiteralCharacters(false);
        return mf.valueToString(texto);
    } catch(Exception e){
        return texto;
    }
}

public static String desformatarString(String texto, String mascara) {
    if(texto == null){
        return null;
    }
    try {
        MaskFormatter mf = new MaskFormatter(mascara);
        mf.setValueContainsLiteralCharacters(false);
        return mf.stringToValue(texto).toString();
    } catch(Exception e){
        return "";
    }
}
Um exemplo de utilização é se você precisa formatar um CNPJ. Imagine que você receba o valor do CNPJ sem pontos e traços, mas precisa mostrá-lo corretamente formatado...você poderia fazer assim:

public static void main(String[] args) {
    try{
        System.out.println(formatarString("54555499869655", "##.###.###/####-##"));
    }catch(Exception e){
        e.printStackTrace();
    }
}
Agora, se você recebe o CNPJ formatado e precisa gravá-lo no banco somente com os números, você poderia fazer:

public static void main(String[] args) {
    try{
        System.out.println(desformatarString("54.555.499/869-655", "##.###.###/####-##"));
    }catch(Exception e){
        e.printStackTrace();
    }
}
Imagine agora que você ainda precisa guardar alguma informação (sem qualquer formatação) que foi formatada mas você não sabe que formato foi utilizado. Utilize então esse método:

public static String somenteNumerosLetras(String texto) {
    if(texto == null){
        return null;
    }
    return texto.replaceAll("[^0-9a-z0-9A-Z]", "");
}
Ele retira tudo o que não for letra e número da string...fácil né!

JSON em Java

Um framework bastante conhecido para trabalhar com JSON em Java é o Jackson. Tudo que vocë precisa fazer é importar 2 jars para o seu projeto e comecar a utilizá-lo. Eles podem ser encontrados em:

http://mvnrepository.com/artifact/org.codehaus.jackson/jackson-core-asl
http://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl

Para transformar objetos comuns Java em JSON, basta fazer:

import java.io.PrintWriter;
import java.io.StringWriter;
import org.codehaus.jackson.map.ObjectMapper;

public static String toJson(Object obj) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    StringWriter jsonValue = new StringWriter();
    mapper.writeValue(new PrintWriter(jsonValue), obj);
    return jsonValue.toString();
}
Para transformar um objeto representado em JSON para um objeto em java, basta fazer:

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.MappingJsonFactory;

public static Object fromJson(String json, Class objectClass) throws Exception {
    JsonFactory f = new MappingJsonFactory();
    JsonParser jp = f.createJsonParser(json);
    Object obj = jp.readValueAs(objectClass);
    return obj;
}
Criando uma classe Pagina, teríamos o seguinte:

public class Pagina {

    private Long id;
    private int numero;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public int getNumero() {
        return numero;
    }
    public void setNumero(int numero) {
        this.numero = numero;
    }

    public String toString() {
        return "Pagina [" id=" + id + " ,numero=" + numero + "]";
    }
}
A representação de um objeto Pagina poderia ser:

{"numero" : 1,"id" : 1}
Agora, executando o método:

public static void main(String[] args) {
    try{
        System.out.println(fromJson("{\"numero\" : 1,\"id\" : 1}", Pagina.class));
    }catch(Exception e){
        e.printStackTrace();
    }
}
Imaginando outra situação, talvez você não tenha a classe que representa o conteúdo de determinado JSON. Nesse caso, a melhor forma é tratar o JSON como ele realmente é, ou seja, como um Mapa de String com objeto.

import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

public static Map fromJson(String json) throws Exception {
   ObjectMapper jsonMapper = new ObjectMapper();
   Map meta = jsonMapper.readValue(json, new TypeReference>() { });	    		
   return meta;
}