Solucionado (ver solução)
Solucionado
(ver solução)
11
respostas

Usando WS localhost

Srs,

O metodo post funciona quando uso o https://www.caelum.com.br/mobile, mas estou querendo testar num servidor localhost. Como faço isso? Segue abaixo a classe deste Curso Android e a classe do Curso WS rest ambos aqui do ALURA.

CLASSE1

public class ServidorProjetos {

    public static void main(String[] args) throws IOException {

        URI uri = URI.create("http://0.0.0.0:8080/");//peguei exemplo da internet
        //URI uri = URI.create("http://localhost:8080/");
        ResourceConfig config = new ResourceConfig().packages("br.com.alura.loja");
        HttpServer server = GrizzlyHttpServerFactory.createHttpServer(uri, config);
        System.out.println("Servidor rodando");
        System.in.read();
        server.stop();
    }
}

CLASSE2

@Path("entregas")
public class EntregaResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String busca(Long id){
        return new EntregaDAO().busca(1l).toJSON();
    }
}

CLASSE3

/**
 * Created by antonio on 27/10/16.
 */
public class WebClient {
    public String post(String json) {
        try {
            URL url = new URL("http://192.168.1.106:8080/entregas?id=1");
            //URL url = new URL("https://www.caelum.com.br/mobile");

            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            //connection.setRequestProperty("Content-type", "application/json");
            //connection.setRequestProperty("Accept", "application/json");

            connection.setDoOutput(false);

            /*PrintStream output = new PrintStream(connection.getOutputStream());
            output.println(json);
            Log.i("json", json);
            */
            connection.connect();

            int responseCode = connection.getResponseCode();
            Log.i("WEBSERVICE", "Código de resposta : " + responseCode);

            Scanner scanner = new Scanner(connection.getInputStream());
            StringBuilder sb = new StringBuilder();
            while (scanner.hasNext()){
                sb.append(scanner.nextLine());
            }
            String resposta = sb.toString();
            Log.d("json", resposta);
            return resposta;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

}

CLASSE4

/**
 * Created by antonio on 27/10/16.
 */
public class EnviaEntregasTask extends AsyncTask<Void, Void, String> {

    @Override
    protected String doInBackground(Void... params) {
        EntregaDAO dao = new EntregaDAO(context);
        List<Entrega> entregas = dao.buscaEntregas();
        dao.close();

        EntregaConverter conversor = new EntregaConverter();
        String json = conversor.converteParaJSON(entregas);

        WebClient client = new WebClient();
        String resposta = client.post(json);
        return resposta;
    }
}

LOG DE ERRO

I/json: {"list":[{"entrega":[{"nome":"Nome1","nota":9},{"nome":"Nome2","nota":7},{"nome":"Nome3","nota":9}]}]}
W/EGL_emulation: eglSurfaceAttrib not implemented
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f0a3fe31cc0, error=EGL_SUCCESS
W/System.err: java.io.FileNotFoundException: http://192.168.1.106:8080/entregas
W/System.err:     at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:206)
W/System.err:     at br.com.teste.agenda.WebClient$override.post(WebClient.java:33)
W/System.err:     at br.com.teste.agenda.WebClient$override.access$dispatch(WebClient.java)
W/System.err:     at br.com.teste.agenda.WebClient.post(WebClient.java:0)
W/System.err:     at br.com.teste.agenda.EnviaEntregasTask.doInBackground(EnviaEntregasTask.java:40)
W/System.err:     at br.com.teste.agenda.EnviaEntregasTask.doInBackground(EnviaEntregasTask.java:17)
W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:292)
W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
W/System.err:     at java.lang.Thread.run(Thread.java:818)
W/EGL_emulation: eglSurfaceAttrib not implemented
W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f0a3fe31bc0, error=EGL_SUCCESS
11 respostas

Olá Antonio,

Qual é exatamente o problema que você está tendo com o código acima? À primeira vista o servidor não está fazendo nada além de ler requisições que chegam ali na porta 8080 então do lado do Android provavelmente você não terá nenhuma resposta..

A classe abaixo é o recurso carrinhos que gostaria de usar na minha aplicação.

CLASSE3

@Path("carrinhos")
public class CarrinhoResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public String busca(Long id){
        return new CarrinhoDAO().busca(1l).toJSON();
    }
}

Certo Antonio, mas o que acontece quando você tenta acessar o seu webservice? Alguma Exception no console ou alguma mensagem de warning?

@Jeferson, editei o questionamento, reordenei as classes, incluí a CLASSE4 e incluí o LOG DO ERRO. Veja se consegue ajudar a resolver. O meu objeto é consumir um WS que esteja rodando no mesmo computador que o emulador esteja.

Antonio, o seu web service foi implementado como um get mas o WebClient está fazendo um post para o servidor. Para fazer um get, você vai precisar mudar o parâmetro do setDoOutput(...) para false já que não estamos enviando nada no corpo da requisição.

Além disso, você vai precisar alterar a URL do WebClient para incluir o parâmetro: ?id= concatenado com o id que você quer buscar.

Após realizar as alterações solicitadas, o erro mudou, conforme abaixo:

LOG ERRO ATUAL

W/EGL_emulation: eglSurfaceAttrib not implemented W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f0a3fe57f00, error=EGL_SUCCESS W/System.err: java.net.ProtocolException: method does not support a request body: GET W/System.err: at com.android.okhttp.internal.http.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:221) W/System.err: at br.com.teste.agenda.WebClient$override.post(WebClient.java:27) W/System.err: at br.com.teste.agenda.WebClient$override.access$dispatch(WebClient.java) W/System.err: at br.com.teste.agenda.WebClient.post(WebClient.java:0) W/System.err: at br.com.teste.agenda.EnviaEntregasTask.doInBackground(EnviaEntregasTask.java:40) W/System.err: at br.com.teste.agenda.EnviaEntregasTask.doInBackground(EnviaEntregasTask.java:17) W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:292) W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237) W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) W/System.err: at java.lang.Thread.run(Thread.java:818) W/EGL_emulation: eglSurfaceAttrib not implemented W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f0a36cae9c0, error=EGL_SUCCESS

Certo, o erro diz que ainda estamos enviando algo no corpo da requisição. E de fato ainda estamos fazendo isso nessa linhas:

PrintStream output = new PrintStream(connection.getOutputStream());
output.println(json);

Neste caso, como estamos fazendo um get, não precisamos escrever nada para o outputStream da conexão. Tente remover essas duas linhas e teste novamente.

Após excluir as linhas solicitadas, a exceção FileNotFoundException voltou a aparecer. Estou achando que o erro está no parser, pois quanto o https://www.caelum.com.br/mobile estava ativo o codigo Android conseguia exibir as informações. Seria possivel passar o link do codigo fonte do WS que responde pelo contexto /mobile? Seria possivel reativar este WS?

Segue abaixo o erro atual.

LOG DO ERRO ATUAL

W/EGL_emulation: eglSurfaceAttrib not implemented W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f0a36cae300, error=EGL_SUCCESS I/json: {"list":[{"entrega":[{"nome":"Nome1","nota":9},{"nome":"Nome2","nota":7},{"nome":"Nome3","nota":9}]}]} W/System.err: java.io.FileNotFoundException: http://192.168.1.106:8080/entregas?id=1 W/System.err: at com.android.okhttp.internal.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:206) W/System.err: at br.com.teste.agenda.WebClient$override.post(WebClient.java:33) W/System.err: at br.com.teste.agenda.WebClient$override.access$dispatch(WebClient.java) W/System.err: at br.com.teste.agenda.WebClient.post(WebClient.java:0) W/System.err: at br.com.teste.agenda.EnviaEntregasTask.doInBackground(EnviaEntregasTask.java:40) W/System.err: at br.com.teste.agenda.EnviaEntregasTask.doInBackground(EnviaEntregasTask.java:17) W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:292) W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:237) W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231) W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112) W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) W/System.err: at java.lang.Thread.run(Thread.java:818) W/EGL_emulation: eglSurfaceAttrib not implemented W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f0a36cae280, error=EGL_SUCCESS

Olá Antonio,

De acordo com a Exception lançada, o problema está ocorrendo na classe HttpURLConnection e isso só pode acontecer se algum parâmetro estiver incorreto ou o web service não estiver atendendo as requisições no endereço solicitado.

Você já deve ter testado mas você consegue acessar o endereço http://192.168.1.106:8080/entregas?id=1 pelo browser e obter a resposta desejada?

Um outro teste para termos mais informações sobre o que pode estar acontecendo é checar o código de resposta da requisição. Para isso, vamos logar esse código colocando o seguinte código antes de tentar ler a resposta do web service:

int responseCode = connection.getResponseCode();
Log.i("WEBSERVICE", "Código de resposta : " + responseCode);

Coloquei as linhas abaixo e verifiquei que o código de retorno foi 415

int responseCode = connection.getResponseCode();
Log.i("WEBSERVICE", "Código de resposta : " + responseCode);

Após algumas pesquisas, comentei as linhas abaixo e o código de retorno passou a ser o 200

//connection.setRequestProperty("Content-type", "application/json");
//connection.setRequestProperty("Accept", "application/json");

Fiz este pequeno ajuste na resposta do método post da classe WebClient

//String resposta = scanner.next();
StringBuilder sb = new StringBuilder();
 while (scanner.hasNext()){
 sb.append(scanner.nextLine());
 }
 String resposta = sb.toString();

EDITEI OS CÓDIGOS CITADOS ANTERIORMENTE!!!

CONCLUSÃO

Finalmente estou conseguindo consumir o WS no localhost(Obrigado @Jeferson)

Não entendi porque os códigos abaixo tiveram que ficar comentados.

//connection.setRequestProperty("Content-type", "application/json");
//connection.setRequestProperty("Accept", "application/json");

@Jeferson,

Você consegue diponibilizar o codigo fonte do projeto que responde pela URL https://www.caelum.com.br/mobile ???

solução!

Ola Antonio!

Que bom que deu certo e realmente faz sentido comentar as linhas, ou melhor, pelo menos uma delas.

O request property Content-type serve para avisar ao servidor qual o formato dos dados que estamos enviando no corpo da requisição. Como nesse caso estamos fazendo um get, esse tipo de request não possui um corpo então não faz sentido especificar que estamos enviando um JSON. Já o segundo que é o Accept, serve para indicar que estamos esperando a resposta em um formato específico (JSON no nosso caso). Perceba que no seu web service você utilizou a anotação @Produces e especificou o tipo da resposta como sendo do tipo JSON.

Acredito que você só precisa comentar a linha do Content-type e voltar com a linha do Accept. Faça um teste pra ver se funciona mesmo.

Sobre o projeto, infelizmente não tenho acesso ao código dele.