"OkHttpClient cannot be converted to MyOkHttpClient" - java

Why wont this compile:
MyOkHttpClient okClient = new MyOkHttpClient.Builder()
.addInterceptor(new AddCookiesInterceptor())
.addInterceptor(new ReceivedCookiesInterceptor()).build();
Incompatible types.
Required:
my.path.util.auth.MyOkHttpClient
Found:
okhttp3.OkHttpClient
This is MY class:
public class MyOkHttpClient extends okhttp3.OkHttpClient implements Authenticator {
private static int MAX_AUTHENTICATE_TRIES = 3;
#Override
public Request authenticate(Route route, Response response) throws IOException {
if (responseCount(response) >= MAX_AUTHENTICATE_TRIES) {
return null; // If we've failed 3 times, give up. - in real life, never give up!!
}
String credential = Credentials.basic(AUTHTOKEN_USERNAME, AUTHTOKEN_PASSWORD);
return response.request().newBuilder().header("Authorization", credential).build();
}
private int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
}

Based on your comments, you incorrectly believe that you are decorating OkHttpClient with custom authentication logic.
Instead, you are unnecessarily extending OkHttpClient and implementing the Authenticator interface. You can simply build the standard OkHttpClient with any custom authenticator you would like.
As such, this is more like what you actually want
public class MyAuthenticator implements Authenticator {
private static int MAX_AUTHENTICATE_TRIES = 3;
#Override
public Request authenticate(Route route, Response response) throws IOException {
if (responseCount(response) >= MAX_AUTHENTICATE_TRIES) {
return null; // If we've failed 3 times, give up. - in real life, never give up!!
}
String credential = Credentials.basic(AUTHTOKEN_USERNAME, AUTHTOKEN_PASSWORD);
return response.request().newBuilder().header("Authorization", credential).build();
}
private int responseCount(Response response) {
int result = 1;
while ((response = response.priorResponse()) != null) {
result++;
}
return result;
}
}
And then when you build your client
OkHttpClient okClient = new OkHttpClient.Builder()
.addInterceptor(new AddCookiesInterceptor())
.addInterceptor(new ReceivedCookiesInterceptor())
.authenticator(new MyAuthenticator())
.build();

Related

Mocking an interface vs class

I have an interface defined as follows:
public interface HttpClient {
public <T> UdemyResponse<T> get(Request request,
JSONUnmarshaler<T> unmarshaller, Gson gson)
throws UdemyException, IOException;
}
I have a class that implements the interface:
public class OkHttp implements HttpClient {
public OkHttpClient client;
final Logger logger = LoggerFactory.getLogger(getClass());
public OkHttp() {
this.client = new OkHttpClient();
}
#Override
public <T> UdemyResponse<T> get(Request request, JSONUnmarshaler<T> unmarshaller, Gson gson)
throws UdemyException, IOException {
int status_code = 0;
String next = null;
String rawJSON = null;
JsonElement jsonelement = null;
Boolean retry = true;
int attempts = 3;
while ((attempts >= 0) && (retry) && status_code != 200) {
try {
Response response = this.client.newCall(request).execute();
rawJSON = response.body().string();
jsonelement = gson.fromJson(rawJSON, JsonElement.class);
next = gson.fromJson(jsonelement.getAsJsonObject().get("next"), String.class);
status_code = response.code();
if (status_code == 401) {
try {
logger.warn("token expired");
TimeUnit.SECONDS.sleep(5);
retry = true;
continue;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if ((status_code / 100) == 5) {
logger.warn("gateway error");
retry = true;
continue;
}
} catch (IOException e) {
e.printStackTrace();
// this exception will be propagated to the main method and handled there to exit the program,
// this exception should end the program.
throw e;
}
attempts -= 1;
retry = false;
}
if (status_code != 200) {
throw new UdemyException();
}
return new UdemyResponse<T>(status_code, next, rawJSON,
unmarshaller.fromJSON(gson, jsonelement.getAsJsonObject()));
}
If I mock my interface I can write test cases for get() method but my get() method uses the this.client and I need to mock that object as well.
In this case, is it better to mock the OkHttp object rather than the interface?
If you are attempting to test get() then you should not mock that method, if you do, what is it that you are testing? You need to mock the other dependencies of get() to help you test it in isolation. In this case if this.client is a dependency of get(), this is what you need to mock.
Edited in response to question changes
This is terrible: (status_code / 100).
Test for the real status code there.
You should do the following:
Create a mock OkHttpClient.
Inject the mock into your test class using reflection.
test the get method.
You may want to change the mocking of the ok thing in the code below,
but you should be able to just use simple Mockito mocks for everything.
Here is some example code:
public class TestOkHttp
{
private static final String VALUE_JSON_STRING "some JSON string for your test";
private OkHttp classToTest;
#Mock
private ClassWithExecute mockClassWithExecute;
#Mock
private OkHttpClient mockOkHttpClient;
#Mock
private Response mockResponse;
#Mock
private ResponseBodyClass mockResponseBodyClass;
#Mock
private Request mockRequest;
private Gson testGson;
#Test
public void get_describeTheTest_expectedResults()
{
final JSONUnmarshaler<someclass> unmarshallerForThisTest = new JSONUnmarshaler<>()
// setup the mocking functionality for this test.
doReturn(desiredStatusCode).when(mockResponse).code();
classToTest.get()
}
#Before
public void preTestSetup()
{
MockitoAnnotations.initMocks(this);
classToTest = new OkHttp();
testGson = new Gson();
doReturn(mockResponse).when(mockClassWithExecute).execute();
doReturn(mockClassWithExecute).when(mockOkHttpClient).newCall(mockRequest);
doReturn(mockResponseBodyClass).when(mockResponse).body();
doReturn(VALUE_JSON_STRING).when(mockResponseBodyClass).string();
ReflectionTestUtils.setField(classToTest,
"client",
mockOkHttpClient);
}
}

Unit testing respository with in MVVM pattern android

I am trying to write unit tests for repository while using MVVM pattern in android.
What i have is a repository which fetched data from the network using retrofit
public class ValidateCbuRepository {
private static ValidateCbuRepository single_instance = null;
private MutableLiveData<CBUValidationImageResponse> data = new MutableLiveData<>();
public static ValidateCbuRepository getInstance() {
if (single_instance == null)
single_instance = new ValidateCbuRepository();
return single_instance;
}
public MutableLiveData<CBUValidationImageResponse> processImage(String encodedString) {
JsonObject postParam = new JsonObject();
postParam.addProperty("image", encodedString);
Api service = RetrofitClientInstance.getRetrofitInstance().create(Api.class);
data.setValue(null);
HttpUrl httpUrl = HttpUrl.parse("some url");
Call<CBUValidationImageResponse> responseCall = service.getProcessedImage_cbu_validation(httpUrl.toString(),postParam);
responseCall.enqueue(new Callback<CBUValidationImageResponse>() {
#Override
public void onResponse(Call<CBUValidationImageResponse> call, Response<CBUValidationImageResponse> response) {
if(response.isSuccessful()) {
CBUValidationImageResponse res = response.body();
CBUValidationImageResponse cbuValidationImageResponse = res;
Log.i("CBU response ",""+cbuValidationImageResponse.toString());
cbuValidationImageResponse.setSuccess(true);
cbuValidationImageResponse.setShowProgres(false);
cbuValidationImageResponse.setError(false);
data.setValue(cbuValidationImageResponse);
}
}
#Override
public void onFailure(Call<CBUValidationImageResponse> call, Throwable t) {
CBUValidationImageResponse cbuValidationImageResponse = new CBUValidationImageResponse();
cbuValidationImageResponse.setError(true);
cbuValidationImageResponse.setShowProgres(false);
data.setValue(cbuValidationImageResponse);
t.printStackTrace();
}
});
return data;
}
}
The unit test part
#Mock
private Observer<CBUValidationImageResponse> observer;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testApiResponse_success() {
Api mockedApiInterface = Mockito.mock(Api.class);
Call<CBUValidationImageResponse> mockedCall = Mockito.mock(Call.class);
Mockito.when(mockedApiInterface.getProcessedImage_cbu_validation(any(),any())).thenReturn(mockedCall);
try {
Mockito.doAnswer(new Answer() {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Callback<CBUValidationImageResponse> callback = invocation.getArgument(0);
CBUValidationImageResponse cbuValidationImageResponse = new CBUValidationImageResponse();
cbuValidationImageResponse.setCBU_code("some code");
cbuValidationImageResponse.setHeight(7);
cbuValidationImageResponse.setBreadth(7);
cbuValidationImageResponse.setLength(7);
callback.onResponse(mockedCall, Response.success(cbuValidationImageResponse));
// or callback.onResponse(mockedCall, Response.error(404. ...);
// or callback.onFailure(mockedCall, new IOException());
return null;
}
}).when(mockedCall).enqueue(any(Callback.class));
ValidateCbuRepository validateCbuRepository = new ValidateCbuRepository();
String encodedString= "";
validateCbuRepository.processImage(encodedString).observeForever(observer);
Getting a null pointer exception at validateCbuRepository.processImage(encodedString).observeForever(observer). Next step is to verify the observer.
I expect the test to pass. What am i doing wrong here?. I did something similar foe view model and the test passes with 100% code coverage.
The retrofit call is asynchronous. Is that the reason why it fails?
Edit : It seems livedata is null while testing causing NPE.

Retrofit: Redirect to LoginActivity if response code is 401

How to start LoginActivity from the interceptor(non-activity class)? I have tried the code (Interceptor) below but not working for me.
Interceptor
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + auth_token_string)
.build();
Response response = chain.proceed(newRequest);
Log.d("MyApp", "Code : "+response.code());
if (response.code() == 401){
Intent intent = new Intent(SplashActivity.getContextOfApplication(), LoginActivity.class);
startActivity(intent);
finish(); //Not working
return response;
}
return chain.proceed(newRequest);
}
}).build();
This is the current solution I'm using, is there any better solution than this? This solution has to keep repeat on every api call.
MainActivity
call.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
if(response.isSuccessful())
{
//success
}
else
{
Intent intent = new Intent(MainActivity.this.getApplicationContext(), LoginActivity.class);
startActivity(intent);
finish();
}
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
}
});
Personally, I would like to suggest using event bus pattern here. You can use greenrobot implementation or whatever you want, since it's more about an architecture approach rather than concrete implementation.
Create event model
public class UnauthorizedEvent {
private static final UnauthorizedEvent INSTANCE = new UnauthorizedEvent();
public static UnauthorizedEvent instance() {
return INSTANCE;
}
private UnauthorizedEvent() {
}
}
Implement custom Interceptor which disptaches event about unauthorized reqeusts
class UnauthorizedInterceptor implements Interceptor {
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
if (response.code() == 401) {
EventBus.getDefault().post(UnauthorizedEvent.instance());
}
return response;
}
}
Create BaseActivity class which handles UnauthorizedEvent
public class BaseActivity extends Activity {
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);
}
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);
}
#Subscribe
public final void onUnauthorizedEvent(UnauthorizedEvent e) {
handleUnauthorizedEvent();
}
protected void handleUnauthorizedEvent() {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
}
}
Prevent launching LoginActivity from LoginActivity
public class LoginActivty extends BaseActivity {
#Override
protected void handleUnauthorizedEvent() {
//Don't handle unauthorized event
}
}
Another approach is to not extending BaseActivity here.
Register your interceptor
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new UnauthorizedInterceptor())
.build();
Pros:
Loose coupling between components
Easaly extending the logic by overriding handleUnauthorizedEvent
No need to rewrite code to use new types of callbacks
Reduce human factor about making mistakes (using Callback instead of BaseCallback)
Cons:
EventBus pattern makes debugging more complicated
One more dependency or own implementation which brings new code to the project
Also, please take into account, that this example doesn't cover multithreading issues. It solves your problem of handling unauthorized requests. Thus, if two requests receive 401 than it is possible that 2 instances of LoginActivity is started.
Consider introducing a custom implementation of retrofit2.Callback interface, e.g. BaseCallback:
public abstract class BaseCallback<T> implements Callback<T> {
private final Context context;
public BaseCallback(Context context) {
this.context = context;
}
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.code() == 401) {
// launch login activity using `this.context`
} else {
onSuccess(response.body());
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
}
abstract void onSuccess(T response);
}
Now, from the caller site you should change new Callback<Token> with new BaseCallback<Token>:
call.enqueue(new BaseCallback<Token>(context) {
#Override
void onSuccess(Token response) {
// do something with token
}
});
Although, this approach doesn't fulfil your following statement:
so I don't have to keep repeat the same code over again for each api call
nevertheless, I cannot come up with a better approach.
The simplest way is to inject activity context in Interceptor instance.
If you are using some DI tools, like Dagger2 or Toothpick it will be very simple. I recommend to use toothpick)
https://github.com/stephanenicolas/toothpick
The most code near by will be in kotlin, because it's my boilerplate code. Those thinks, that you are need to solve your problem i will write in Java.
The solution will be like this:
#Qualifier
annotation class BackendUrl
class ActivityModule(activity: BaseActivity): Module() {
init {
bind(Activity::class.java).toInstance(activity)
}
}
class NetworkModule: Module() {
init {
bind(String::class.java).withName(BackendUrl::class.java).toInstance(Constants.URL)
bind(Gson::class.java).toInstance(GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss").create())
bind(CacheHolder::class.java).toProvider(CacheProvider::class.java).singletonInScope()
bind(OkHttpClient::class.java).toProvider(OkHttpProvider::class.java).instancesInScope()
bind(BackendApi::class.java).toProvider(BackendApiProvider::class.java).instancesInScope()
bind(RedirectInterceptor::class.java).to(RedirectInterceptor::class.java)
}
}
Than you need to create Providers for injection dependency
class BackendApiProvider #Inject constructor(
private val okHttpClient: OkHttpClient,
private val gson: Gson,
#BackendUrl private val serverPath: String
) : Provider<BackendApi> {
override fun get() =
Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gson))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(okHttpClient)
.baseUrl(serverPath)
.build()
.create(BackendApi::class.java)
}
And your redirect interceptor:
public class RedirectInterceptor implements Interceptor {
private final Context context;
#Inject
public RedirectInterceptor(Activity context) {
this.context = context;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request newRequest = chain.request().newBuilder()
.build();
Response response = chain.proceed(newRequest);
Log.d("MyApp", "Code : "+response.code());
if (response.code() == 401){
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent);
((Activity) context).finish();
return response;
}
return chain.proceed(newRequest);
}
}
Oh, yes. For Authorization header will be better to create new instance of another interceptor
class HeaderInterceptor(private val token: String?) : Interceptor {
#Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val newRequest = request.newBuilder()
Log.d(TAG, "token: $token")
if (token != null && token.isNotBlank()) {
newRequest.addHeader("Authorization", "Bearer $token")
}
return chain.proceed(newRequest.build())
}
companion object {
private val TAG = HeaderInterceptor::class.java.toString()
}
}
And your OkhttpProvder
class OkHttpProvider #Inject constructor(cacheHolder: CacheHolder, prefs: IPreferences, redirectInterceptor: RedirectInterceptor) : Provider<OkHttpClient> {
private val client: OkHttpClient
init {
val builder = OkHttpClient.Builder()
builder
.addNetworkInterceptor(redirectInterceptor)
.addNetworkInterceptor(HeaderInterceptor(prefs.getAuthToken()))
.readTimeout(30, TimeUnit.SECONDS)
.cache(cacheHolder.okHttpCache)
client = builder.build()
}
override fun get() = client
}
Thats all! Now, you just only need to place you modules in right scopes.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.init_view)
Toothpick.openScopes("activity scope").apply {
installModules(ActivityModule(this#YourActivity))
Toothpick.inject(this#YourActivity, this)
}
Toothpick.openScopes("activity scope", "network scope").apply {
installModules(NetworkModule())
}
// your activity code
}
This is how interceptor worked for handling 401 globally
public class ResponseHeaderInterceptor implements Interceptor {
private final Context context;
public ResponseHeaderInterceptor(Context context) {
this.context = context;
}
#NotNull
#Override
public Response intercept(#NotNull Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
if(response.code() == 401){
SharedPreferences pref = context.getSharedPreferences(Constants.PREFERENCES, 0);
String userName = pref.getString("key_user_email", "");
//clear shared preferences
pref.edit().clear().apply();
Bundle params = new Bundle();
params.putString("user", userName);
FirebaseAnalytics.getInstance(context).logEvent(Constants.USER_UNAUTHORIZED_EVENT, params);
Intent intent = new Intent(this.context, IntroActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.context.startActivity(intent);
}
return response;
}
}
adding to okhttp client of retrofit
var okHttpClient: OkHttpClient = OkHttpClient()
.newBuilder()
.addInterceptor(ResponseHeaderInterceptor(MyApplication.getMyApplicationContext()))//Header interceptor for logging network responses
.build()
private var retrofit: Retrofit? = null
val client: Retrofit?
get() {
if (retrofit == null) {
retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(BuildConfig.SERVER)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
return retrofit
}
Generalized Solution:
You can solve it by generalizing the error handling. You can use custom CallAdapterFactory to the Retrofit builder. Please refer below classes :
RxErrorHandlingCallAdapterFactory :
public class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
private static Context mContext = null;
private final RxJava2CallAdapterFactory original;
private RxErrorHandlingCallAdapterFactory() {
original = RxJava2CallAdapterFactory.create();
}
public static CallAdapter.Factory create(Context context) {
mContext = context;
return new RxErrorHandlingCallAdapterFactory();
}
#Override
public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit));
}
private static class RxCallAdapterWrapper<R> implements CallAdapter<R, Object> {
private final Retrofit retrofit;
private final CallAdapter<R,
Object> wrapped;
public RxCallAdapterWrapper(Retrofit retrofit, CallAdapter<R, Object> wrapped) {
this.retrofit = retrofit;
this.wrapped = wrapped;
}
#Override
public Type responseType() {
return wrapped.responseType();
}
#Override
public Object adapt(Call<R> call) {
Object result = wrapped.adapt(call);
if (result instanceof Single) {
return ((Single) result).onErrorResumeNext(new Function<Throwable, SingleSource>() {
#Override
public SingleSource apply(#NonNull Throwable throwable) throws Exception {
return Single.error(asRetrofitException(throwable));
}
});
}
if (result instanceof Observable) {
return ((Observable) result).onErrorResumeNext(new Function<Throwable, ObservableSource>() {
#Override
public ObservableSource apply(#NonNull Throwable throwable) throws Exception {
return Observable.error(asRetrofitException(throwable));
}
});
}
if (result instanceof Completable) {
return ((Completable) result).onErrorResumeNext(new Function<Throwable, CompletableSource>() {
#Override
public CompletableSource apply(#NonNull Throwable throwable) throws Exception {
return Completable.error(asRetrofitException(throwable));
}
});
}
return result;
}
private RetrofitException asRetrofitException(Throwable throwable) {
// We had non-200 http error
Log.v("log", "eror");
throwable.printStackTrace();
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
final Response response = httpException.response();
//if ((mContext instanceof Activity)) {
String s = "Something went wrong."; //mContext.getString(R.string.something_went_wrong);
try {
s = new JSONObject(response.errorBody().string()).getString("message");
if (response.code() == 401) { // 401 Unauthorized
Intent intent = new Intent(mContext, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mContext.startActivity(intent);
}
} catch (JSONException | IOException e) {
e.printStackTrace();
}
return RetrofitException.unexpectedError(s, response, retrofit);
//showErrorDialog(mContext, response);
//}
// return RetrofitException.httpError(response.errorBody().toString(), response, retrofit);
}
// A network error happened
if (throwable instanceof IOException) {
return RetrofitException.networkError((IOException) throwable);
}
// We don't know what happened. We need to simply convert to an unknown error
return RetrofitException.unexpectedError(throwable);
}
}
}
RetrofitException :
public class RetrofitException extends RuntimeException {
private final String url;
private final Response response;
private final Kind kind;
private final Retrofit retrofit;
RetrofitException(String message, String url, Response response, Kind kind, Throwable exception, Retrofit retrofit) {
super(message, exception);
this.url = url;
this.response = response;
this.kind = kind;
this.retrofit = retrofit;
}
public static RetrofitException httpError(String url, Response response, Retrofit retrofit) {
String message = response.code() + " " + response.message();
return new RetrofitException(message, url, response, Kind.HTTP, null, retrofit);
}
public static RetrofitException networkError(IOException exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.NETWORK, exception, null);
}
public static RetrofitException unexpectedError(Throwable exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.UNEXPECTED, exception, null);
}
public static RetrofitException unexpectedError(String s, Response response, Retrofit retrofit) {
return new RetrofitException(s, null, null, Kind.UNEXPECTED, null, null);
}
/**
* The request URL which produced the error.
*/
public String getUrl() {
return url;
}
/**
* Response object containing status code, headers, body, etc.
*/
public Response getResponse() {
return response;
}
/**
* The event kind which triggered this error.
*/
public Kind getKind() {
return kind;
}
/**
* The Retrofit this request was executed on
*/
public Retrofit getRetrofit() {
return retrofit;
}
/**
* HTTP response body converted to specified {#code type}. {#code null} if there is no
* response.
*
* #throws IOException if unable to convert the body to the specified {#code type}.
*/
public <T> T getErrorBodyAs(Class<T> type) throws IOException {
if (response == null || response.errorBody() == null) {
return null;
}
Converter<ResponseBody, T> converter = retrofit.responseBodyConverter(type, new Annotation[0]);
return converter.convert(response.errorBody());
}
/**
* Identifies the event kind which triggered a {#link RetrofitException}.
*/
public enum Kind {
/**
* An {#link IOException} occurred while communicating to the server.
*/
NETWORK,
/**
* A non-200 HTTP status code was received from the server.
*/
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
}
Retrofit Builder :
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(RxErrorHandlingCallAdapterFactory.create(context))
.addConverterFactory(GsonConverterFactory.create())
.baseUrl(API_URL)
.client(client)
.build();
You can handle 401 in RxErrorHandlingCallAdapterFactory and other errors through Throwable.

How to pass Header in Retrofit 2.1.0

Hi From last two I'm stuck with this retrofit any one please help me.I have tried so many method to pass header in retrofit could but i couldn't im using Retrofit 2.0.1
build.gradle
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
compile 'com.squareup.okhttp:okhttp:2.7.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
And in
ApiClientHeader.jav
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ApiClientHeader {
public static final String BASE_URL = "URL";
private static Retrofit retrofit = null;
public static Retrofit getClient(final String token) {
OkHttpClient okClient = new OkHttpClient.Builder()
.addInterceptor(
new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", "Bearer " + token)
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
})
.build();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(okClient)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
And In my
ApiInterface.java
#GET("profile")
Call<JsonObject> getProfile();
And In My Activity i am just calling function
private void getProfileData()
{
Singleton single = new Singleton();
String auth = single.getAuthorization();
Log.d("===========>>>>>>",auth);
ApiInterface apiService =
ApiClientHeader.getClient(auth).create(ApiInterface.class);
//showProgress(true);
Call<JsonObject> profileResponse = apiService.getProfile();
profileResponse.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
//showProgress(false);
Log.d("============>"," Call Request " +String.valueOf(call.request().toString()));
Log.d("============>", " Response code " + String.valueOf(response.code()));
// Log.d("============>", " Response Body " + String.valueOf(response.body().toString()));
if(response.code() == HttpURLConnection.HTTP_OK)
{
}
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
//showProgress(false);
Log.d("============>"," Call Request " +String.valueOf(call.request().toString()));
Log.d("============>"," Call Request " +String.valueOf(call.request().headers()));
Log.d("=======>", "Failure" + t.getMessage());
}
});
}
Still I am getting 403 Invalid acces.
Here i have not used any POJO class to send or receive data. Please help me.
You have to pass your authentication string like this
#GET("profile")
Call<JsonObject> getProfile((#Header("Authorization") String authorization))
#Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
#GET("users/{username}")
Call<User> getUser(#Path("username") String username);
more info on documentation
I found one of the best link for Token based authentication using Retrofit 1.9 + OkHttp 2.4
You can add NetworkInterceptor, I have used it in my demo like:
httpClient.addNetworkInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
// Add authorization header with updated authorization value to intercepted request
Request authorisedRequest = originalRequest.newBuilder()
.header("Authorization", AccountAuthenticator.getAccessTokenWithTokenType(mContext))
.build();
return chain.proceed(authorisedRequest);
}
});
Dependencies:
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
Thank you.
Try below code with your class, It is working for me:
final RestAdapter restAdapter = new RestAdapter.Builder().setClient(client).setLogLevel(RestAdapter.LogLevel.FULL).setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade requestFacade) {
requestFacade.addHeader("key", "value");
requestFacade.addHeader("X-Requested-With", "XMLHttpRequest");
}
}).setConverter(new GsonConverter(gson)).setEndpoint(context.getString(R.string.base_url)).build();
Edit Post :
public class RestClient {
// private static final String BASE_URL = "http://api.plumperfect.com";
private WebServicesInterface apiService;
private static RestClient instance;
public RestClient(Context context) {
instance = this;
final Gson gson = new GsonBuilder().registerTypeAdapterFactory(new ItemTypeAdapterFactory()).setDateFormat("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'").create();
// final int cacheSize = 10 * 1024 * 1024; // 10 MiB
// final File cacheDirectory = new File(context.getCacheDir().getAbsolutePath(), "HttpCache");
// final OkHttpClient client = new OkHttpClient();
// Cache cache;
// try {
// cache = new Cache(cacheDirectory, cacheSize);
// client.setCache(cache);
// } catch (IOException e) {
// e.printStackTrace();
// }
final OkHttpClient okHttpClient = new OkHttpClient();
final Client client = new OkClient(okHttpClient);
final RestAdapter restAdapter = new RestAdapter.Builder().setClient(client).setLogLevel(RestAdapter.LogLevel.FULL).setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade requestFacade) {
requestFacade.addHeader("key", "value");
requestFacade.addHeader("X-Requested-With", "XMLHttpRequest");
}
}).setConverter(new GsonConverter(gson)).setEndpoint(context.getString(R.string.base_url)).build();
apiService = restAdapter.create(WebServicesInterface.class);
}
public WebServicesInterface getApiService() {
return apiService;
}
public static RestClient getInstance() {
return instance;
}
}
Secound Class :
public class ItemTypeAdapterFactory implements TypeAdapterFactory {
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
return new TypeAdapter<T>() {
public void write(JsonWriter out, T value) throws IOException {
delegate.write(out, value);
}
public T read(JsonReader in) throws IOException {
JsonElement jsonElement = elementAdapter.read(in);
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject.has(Constants.DATA) && jsonObject.get(Constants.DATA).isJsonObject()) {
jsonElement = jsonObject.get(Constants.DATA);
}
}
return delegate.fromJsonTree(jsonElement);
}
}.nullSafe();
}
}

Trying to show the #Path in #Get in Download Progress in Retrofit

Trying to show the #Path in #Get in Download Progress in Retrofit
I wanted to show the passed #Path during progress update using ProgressResponseBody
this is my ProgressListener
public interface ProgressListener {
void update(long bytesRead, long contentLength, boolean done , String param);
}
this is my ProgressResponseBody
public class ProgressResponseBody extends ResponseBody {
private final Response response;
private final ResponseBody responseBody;
private final ProgressListener progressListener;
private BufferedSource bufferedSource;
public ProgressResponseBody(Response response, ProgressListener progressListener) {
this.response = response;
this.responseBody = response.body();
this.progressListener = progressListener;
}
#Override public MediaType contentType() {
return responseBody.contentType();
}
#Override public long contentLength() {
return responseBody.contentLength();
}
#Override public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
#Override public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
// read() returns the number of bytes read, or -1 if this source is exhausted.
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
progressListener.update(totalBytesRead, responseBody.contentLength(), bytesRead == -1 , "Dont know how to get it here");
return bytesRead;
}
};
}
}
and this is my Retrofit Library
#Module(
library = true,
complete = false
)
public class RetrofitLibrary {
#Provides
#Singleton
#Named(Constants.MAP_HTTP_CONSTANTS)
public Retrofit provideRetrofitForHttp(#ForApplication Context context , #ForEventBus EventBus mBus){
final OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse, new ProgressListener(){
#Override
public void update(long bytesRead, long contentLength, boolean done, String param) {
// sending data using EventBus here
}
}))
.build();
}
})
.build();
return new Retrofit.Builder()
.baseUrl("URL here")
.client(client)
.build();
}
}
this is my DownloadService
#GET("/someurl/{map_name}.mbtiles")
#Streaming
Call<ResponseBody> downloadMap(#Path("map_name") String map_name );
Now Im wondering if ever this is is going to work, I dont know how to get the #Path specifically map_name.

Categories

Resources