StackOverflowError Retrofit With Basic Authentication

0

I have a ServiceGenerator that creates the retrofit for min, it works fine when I login and password for it, but when I try to use it without these options, my code goes into a loop and crash the app like this:

12-22 01:27:55.088 8500-8500/doupenglish.com.br.doup D/Error: ERR: stack=java.lang.StackOverflowError: stack size 8MB
at doupenglish.com.br.doup.Service.ServiceGenerator.createService(ServiceGenerator.java:29)
at doupenglish.com.br.doup.Service.ServiceGenerator.createService(ServiceGenerator.java:35)
at doupenglish.com.br.doup.Service.ServiceGenerator.createService(ServiceGenerator.java:35)
at doupenglish.com.br.doup.Service.ServiceGenerator.createService(ServiceGenerator.java:35) 
etc

My ServiceGenerator class:

package doupenglish.com.br.doup.Service;

import android.text.TextUtils;

import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ServiceGenerator {

    private static final String API_BASE_URL = "http://api.doupenglish.com.br/";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    private static Retrofit retrofit = builder.build();

    public static <S> S createService(Class<S> serviceClass) {
        return createService(serviceClass, null, null);
    }

    public static <S> S createService(
            Class<S> serviceClass, String username, String password) {
        if (!TextUtils.isEmpty(username)
                && !TextUtils.isEmpty(password)) {
            String authToken = Credentials.basic(username, password);
            return createService(serviceClass, authToken);
        }

        return createService(serviceClass, null, null);
    }

    public static <S> S createService(
            Class<S> serviceClass, final String authToken) {
        if (!TextUtils.isEmpty(authToken)) {
            AuthenticationInterceptor interceptor =
                    new AuthenticationInterceptor(authToken);

            if (!httpClient.interceptors().contains(interceptor)) {
                httpClient.addInterceptor(interceptor);

                builder.client(httpClient.build());
                retrofit = builder.build();
            }
        }

        return retrofit.create(serviceClass);
    }
}

Interceptor

class AuthenticationInterceptor implements Interceptor {
    private String authToken;

    public AuthenticationInterceptor(String token) {
        this.authToken = token;
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();

        Request.Builder builder = original.newBuilder()
                .header("Authorization", authToken);

        Request request = builder.build();
        return chain.proceed(request);
    }
}

And finally the call

    ApiInterface apidoup = ServiceGenerator.createService(ApiInterface.class);
    Call<List<NoticiaModel>> noticias = apidoup.getnoticias();
    noticias.enqueue(new Callback<List<NoticiaModel>>() {
        @Override
        public void onResponse(Call<List<NoticiaModel>> call, Response<List<NoticiaModel>> response) {
            if (response.isSuccessful()){
                //List<NoticiaModel> a = response.body();
                rv_noticas.setAdapter(new AdapterNoticias(getContext(),response.body()));
                mProgressDialog.dismiss();
            }else{
                Log.e(TAG, "onResponse: Erro API noticias " + response.code());
                mProgressDialog.dismiss();
            }
        }
        @Override
        public void onFailure(Call<List<NoticiaModel>> call, Throwable t) {
            Log.e(TAG, "onResponse: Erro API Conexao " + t);
            mProgressDialog.dismiss();

        }
    });

Resolved:

    package doupenglish.com.br.doup.Service;

import android.text.TextUtils;

import okhttp3.Credentials;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class ServiceGenerator {

    private static final String API_BASE_URL = "http://api.doupenglish.com.br";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    private static Retrofit.Builder builder =
            new Retrofit.Builder()
                    .baseUrl(API_BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create());

    private static Retrofit retrofit = builder.build();

    public static <S> S createService(Class<S> serviceClass) {
        return createService(serviceClass, null, null);
    }

    public static <S> S createService( Class<S> serviceClass, String username, String password) {
        if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)) {
            String authToken = Credentials.basic(username, password);
            if (!TextUtils.isEmpty(authToken)) {
                AuthenticationInterceptor interceptor =  new AuthenticationInterceptor(authToken);
                if (!httpClient.interceptors().contains(interceptor)) {
                    httpClient.addInterceptor(interceptor);
                    builder.client(httpClient.build());
                    retrofit = builder.build();
                }
            }
            return retrofit.create(serviceClass);
        }else{
            return retrofit.create(serviceClass);
        }
    }

}
    
asked by anonymous 22.12.2017 / 02:33

1 answer

1

If the login password is not filled, you invoke the same createService(Class, String, String) method again, infinitely. This causes the stack to overflow. You need to rethink your logic at this point:

public static <S> S createService(Class<S> serviceClass, String username, String password) {
    ...
    return createService(serviceClass, null, null);
}
    
22.12.2017 / 10:28