Unauthorized when send POST method - android

I have a problem with Retrofit and post method.
My GET method with authentication work but POST isn't working.
I logged without any problems, and do any GET method.
When I am trying send some data to REST API (Spring) I get this error:
Response{protocol=http/1.1, code=401, message=, url=http://10.101.12.31:8080/add}
My Code:
DataAPI.java:
public class DataAPI {
private static final String BASE_URL = "http://10.101.12.31:8080/";
static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(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);
}
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);
}
public static DepartmentService getDepartmentService() {
return retrofit.create(DepartmentService.class);
}
}
AuthenticationInterceptor.java:
public 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()
.addHeader("Authorization", authToken);
Request request = builder.build();
return chain.proceed(request);
}
}
Web interface:
public interface Service {
#POST("/add")
Call<Void> addUser(#Body User user);
}
Method:
public void buttonOne(View v) {
DataAPI.createService(Service.class, getIntent().getStringExtra("authToken"))
.addUser(user)).enqueue(new Callback<User>() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
System.out.println(response);
}
#Override
public void onFailure(Call<User> call, Throwable t) {
Toast.makeText(getApplicationContext(),t.toString(),Toast.LENGTH_SHORT).show();
}
});
}

Related

how to set header in post request of retrofit?

I am trying to implement sendOTP of MSG91.There I have to API ,one for generating otp and another one for verifying otp.But there in post reuest I have to set a header ,so how can I set header in retrofit.I am attaching a pic of what to do.Please help me.enter image description here
post request:-
public class GenerateOTPRequest {
String countryCode;
String mobileNumber;
public GenerateOTPRequest(String countryCode, String mobileNumber) {
this.countryCode = countryCode;
this.mobileNumber = mobileNumber;
}
public String getCountryCode() {
return countryCode;
}
public void setCountryCode(String countryCode) {
this.countryCode = countryCode;
}
public String getMobileNumber() {
return mobileNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
}
Response:-
public class GenerateOTPResponse {
#SerializedName("status")
#Expose
String status;
#SerializedName("response")
#Expose
String response;
public GenerateOTPResponse(String status, String response) {
this.status = status;
this.response = response;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
}
my main activity:-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_verify_otp);
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/opensanslight.ttf")
.setFontAttrId(R.attr.fontPath)
.build()
);
getSupportActionBar().setTitle("Verify Your OTP");
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
enterOTP = (EditText) findViewById(R.id.enter_otp);
verifyOTP = (Button) findViewById(R.id.verify_otp);
didntReceiveOTP = (TextView) findViewById(R.id.verify_otp_didnt_receive_otp);
sharedpreferences = getSharedPreferences(MyPREFERENCES, Context.MODE_PRIVATE);
phone = sharedpreferences.getString(Phone, "notPresent");
Log.d("jkhdds: ", "" + phone);
GenerateOTPRequest generateOTPRequest = new GenerateOTPRequest("","");
generateOTPRequest.setCountryCode("91");
generateOTPRequest.setMobileNumber(phone);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("application-key", "oEBg-3z4hgcv5X8sk_AYdVDiqpGCN02G3cFRjCK0er6MWhuSHAQDRT3TuJKxzOI__2H3D_gZZWeMJsns92zEm4LlksdilXYePbiFZRc1OLZxZd1DmSQOlmM-MIhDrXOqefgIVJX_deqP0QfRoBZ-PtlqpCtZFRqem1kl_J2Vra8=")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client = httpClient.build();
Retrofit retrofit1 = new Retrofit.Builder()
.baseUrl("https://sendotp.msg91.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
final API service1 = retrofit1.create(API.class);
Call<GenerateOTPResponse> call = service1.generateOTP(generateOTPRequest);
call.enqueue(new Callback<GenerateOTPResponse>() {
#Override
public void onResponse(Call<GenerateOTPResponse> call, retrofit2.Response<GenerateOTPResponse> response) {
//GenerateOTPResponse generateOTPResponse = response.body();
//String status = otpResponse.getStatus();
Log.d("otp response " , response.body().getResponse());
}
#Override
public void onFailure(Call<GenerateOTPResponse> call, Throwable t) {
}
});
Log.d("Tag", String.valueOf(enterOTP.getText()));
OkHttpClient.Builder httpClient1 = new OkHttpClient.Builder();
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request request = original.newBuilder()
.header("application-key", "oEBg-3z4hgcv5X8sk_AYdVDiqpGCN02G3cFRjCK0er6MWhuSHAQDRT3TuJKxzOI__2H3D_gZZWeMJsns92zEm4LlksdilXYePbiFZRc1OLZxZd1DmSQOlmM-MIhDrXOqefgIVJX_deqP0QfRoBZ-PtlqpCtZFRqem1kl_J2Vra8=")
.method(original.method(), original.body())
.build();
return chain.proceed(request);
}
});
OkHttpClient client1 = httpClient1.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://sendotp.msg91.com/api/")
.addConverterFactory(GsonConverterFactory.create())
.client(client1)
.build();
final API service = retrofit.create(API.class);
Log.d("Tag",enterOTP.getText().toString());
Log.d("Tag","fuck u");
verifyOTP.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final VerifyOTPRequest verifyOTPRequest = new VerifyOTPRequest("","","");
verifyOTPRequest.setCountryCode("91");
verifyOTPRequest.setMobileNumber(phone);
verifyOTPRequest.setOneTimePassword(enterOTP.getText().toString());
Log.d("Tag",enterOTP.getText().toString());
Call<VerifyOTPResponse> call = service.verifyOTP(verifyOTPRequest);
call.enqueue(new Callback<VerifyOTPResponse>() {
#Override
public void onResponse(Call<VerifyOTPResponse> call, retrofit2.Response<VerifyOTPResponse> response) {
Log.d("Tag", String.valueOf(response.body()));
String message = response.body().getStatus();
Log.d("Tag",message);
if (message.equals("success")) {
Toast.makeText(getApplicationContext(), "Successfully Verified", Toast.LENGTH_LONG).show();
Intent intent1 = getIntent();
String parentActivityName = intent1.getStringExtra("activity");
if (parentActivityName.equals("signup")) {
Intent selectSubject = new Intent(VerifyOTPActivity.this, SelectSubjectActivity.class);
progressDialog.dismiss();
startActivity(selectSubject);
} else {
Intent changepassword = new Intent(VerifyOTPActivity.this, ChangePasswordActivity.class);
progressDialog.dismiss();
startActivity(changepassword);
}
}
Log.d("message csdkhds", "" + message);
Log.d("phonre : ", " " + phone);
}
#Override
public void onFailure(Call<VerifyOTPResponse> call, Throwable t) {
}
});
}
});
}
my interface:-
#POST("generateOTP")
Call<GenerateOTPResponse> generateOTP(#Body GenerateOTPRequest generateOTPRequest);
#POST("verifyOTP")
Call<VerifyOTPResponse> verifyOTP(#Body VerifyOTPRequest verifyOTPRequest);
Just use annotation:
public interface Service {
#Headers("application-Key", your key)
#GET("/example")
Call<List<Example>> getExamples();
}
All examples are available here: https://futurestud.io/tutorials/retrofit-add-custom-request-header
You can use #Header annotation for your api method as it is clearly stated in a documentation https://square.github.io/retrofit/
#Headers("XYZ: value")
you can set it in your base retrofit file
request = original.newBuilder()
.header("header key", "your header)
.header("x-requested-with", "XMLHttpRequest")
.method(original.method(), original.body())
.build();
okhttp3.Response response = chain.proceed(request);
#Header
this is a Retrofit specific annotation which will allow you the pass the request headers to the targeting HTTP endpoint, where every argument represents a request header entry.

Listen to all responses globally?

If a user is banned on my app, my server returns the following response:
return response()->json([
'banned' => 'You are banned.'
], 403);
So whenever a Retrofit request is made to the server, I need to be able to globally check and read all responses in case the user has been banned.
Here is my ApiClient.java that handles Retrofit:
public class ApiClient {
public static final String API_URL = "http://www.website.com/api/";
private static int defaultTimeout = 30;
private static OkHttpClient.Builder httpClient =
new OkHttpClient.Builder();
private static Gson gson = new GsonBuilder()
.setLenient()
.create();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(new NullOnEmptyConverterFactory())
.addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(API_URL);
private static Retrofit retrofit = builder.build();
public static Retrofit getRetrofit() {
return retrofit;
}
public static <S> S createService(Class<S> serviceClass, Context context) {
return createService(serviceClass, context, null);
}
public static <S> S createService(Class<S> serviceClass, Context context, final String authToken) {
return createService(serviceClass, context, authToken, defaultTimeout);
}
public static <S> S createService(Class<S> serviceClass, Context context, final String authToken, int timeout) {
if (authToken != null) {
TokenInterceptor tokenInterceptor = new TokenInterceptor(authToken);
if (!httpClient.interceptors().contains(tokenInterceptor)) {
httpClient.addInterceptor(tokenInterceptor);
}
TokenAuthenticator tokenAuthenticator = new TokenAuthenticator(context, authToken);
httpClient.authenticator(tokenAuthenticator);
}
httpClient.connectTimeout(timeout, TimeUnit.SECONDS);
httpClient.writeTimeout(timeout, TimeUnit.SECONDS);
httpClient.readTimeout(timeout, TimeUnit.SECONDS);
builder.client(httpClient.build());
retrofit = builder.build();
return retrofit.create(serviceClass);
}
}
How can I modify this so that it checks every response from my server to check if the user has been banned? Would I create an interceptor in this case? How?
Yeah just create an interceptor that looks for 403 responses.
public class BannedInterceptor implements Interceptor {
#Override
public Response intercept(#NonNull Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
if (response.code() == 403) {
throw new IOException("user banned!");
}
return response;
}
}
And add it to your OkHttp client.
httpClient.addInterceptor(new BannedInterceptor())

Retrofit and OkHttp basic authentication

I am trying to add basic authentication (username and password) to a Retrofit OkHttp client. This is the code I have so far:
private static Retrofit createMMSATService(String baseUrl, String user, String pass) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
I am using Retrofit 2.2 and this tutorial suggests using AuthenticationInterceptor, but this class is not available.
Where is the correct place to add the credentials? Do I have to add them to my interceptor, client or Retrofit object? And how do I do that?
Find the Solution
1.Write a Interceptor class
import java.io.IOException;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
public class BasicAuthInterceptor implements Interceptor {
private String credentials;
public BasicAuthInterceptor(String user, String password) {
this.credentials = Credentials.basic(user, password);
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request authenticatedRequest = request.newBuilder()
.header("Authorization", credentials).build();
return chain.proceed(authenticatedRequest);
}
}
2.Finally, add the interceptor to an OkHttp client
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new BasicAuthInterceptor(username, password))
.build();
Retrofit 2
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
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);
}
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);
}
}
Retrofit 1.9
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setClient(new OkClient(new OkHttpClient()));
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 (username != null && password != null) {
// concatenate username and password with colon for authentication
String credentials = username + ":" + password;
// create Base64 encodet string
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", basic);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass);
}
}
AuthenticationInterceptor.java
public 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);
}
}
Usage
Retrofit 2
Interface
public interface LoginService {
#POST("/login")
Call<User> basicLogin();
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();
call.enqueue(new Callback<User >() {
#Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// user object available
} else {
// error response, no access to resource?
}
}
#Override
public void onFailure(Call<User> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
Retrofit 1.9
Interface
public interface LoginService {
#POST("/login")
void basicLogin(Callback<User> cb);
}
Requester
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
loginService.basicLogin(new Callback<User>() {
#Override
public void success(User user, Response response) {
// user object available
}
#Override
public void failure(RetrofitError error) {
// handle errors, too
}
});
More information see here.
add header interceptor
public class HeaderInterceptor implements Interceptor {
private PreferencesRepository mPrefs;
private String mAuth;
public HeaderInterceptor(PreferencesRepository p) {
mPrefs = p;
}
#Override
public Response intercept(Chain chain) throws IOException {
mAuth = (mPrefs.getAuthToken() != null)?mPrefs.getAuthToken():"";
Request r = chain.request()
.newBuilder()
.addHeader("Accept", "application/json")
// authorization token here
.addHeader("Authorization", "Bearer" + mAuth)
.build();
return chain.proceed(r);
}
}
add cacheinterceptor (optional)
public class CacheInterceptor implements Interceptor {
Context mContext;
public CacheInterceptor(Context context) {
this.mContext = context;
}
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (request.method().equals("GET")) {
if (DeviceUtils.isConnected(mContext)) {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "only-if-cached")
.build();
} else {
request = request.newBuilder()
.header(Constant.CACHE_CONTROL, "public, max-stale=2419200")
.build();
}
}
Response originalResponse = chain.proceed(request);
return originalResponse.newBuilder()
.header(Constant.CACHE_CONTROL, "max-age=600")
.build();
}
}
implement it
HttpLoggingInterceptor logger = new HttpLoggingInterceptor();
logger.setLevel(HttpLoggingInterceptor.Level.BODY);
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MiB
Cache cache = new Cache(new File(mContext.getCacheDir(), "http"), SIZE_OF_CACHE);
new OkHttpClient.Builder()
.addInterceptor(logger)
.addInterceptor(new HeaderInterceptor(u))
.cache(cache)
.addNetworkInterceptor(new CacheInterceptor(mContext))
.connectTimeout(Constant.CONNECTTIMEOUT, TimeUnit.SECONDS)
.readTimeout(Constant.READTIMEOUT, TimeUnit.SECONDS)
.writeTimeout(Constant.WRITETIMEOUT, TimeUnit.SECONDS)
.build();
Of course using auth interceptor is correct way (as explained in other answers). Although, if you need basic authentication only for single call, then auth header can be added directly in Retrofit request:
import okhttp3.Credentials
// Create credentials
val login = "some login"
val password = "some password"
// Below code will create correct Base64 encoded Basic Auth credentials
val credentials = Credentials.basic(login, password)
// Then in your Retrofit API interface
interface MyApi {
#POST("get_user")
fun getUser(#Header("Authorization") credentials: String): ResponseBody
}

HTTPS not working with OkHttp3 and Retrofit2

Well, I'm having problems to connect with my https URL, all works with postman, but I can´t do it with my Android App, Can someone help me?
Image of code.
public class NetworkUtil{
public static RetrofitInterface getRetrofit(){
return new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build().create(RetrofitInterface.class);
}
public static RetrofitInterface getRetrofit(String email, String password) {
String credentials = email + ":" + password;
String basic = "Basic " + Base64.encodeToString(credentials.getBytes(),Base64.NO_WRAP);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.addHeader("Authorization", basic)
.method(original.method(),original.body());
return chain.proceed(builder.build());
});
return new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(httpClient.build())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build().create(RetrofitInterface.class);
}
I need to authenticate the tokens, how can i add that to the okhttp?
public static RetrofitInterface getRetrofit(String token) {
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
httpClient.addInterceptor(chain -> {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.addHeader("x-access-token", token)
.method(original.method(),original.body());
return chain.proceed(builder.build());
});
return new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(okHttpClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build().create(RetrofitInterface.class);
}
}
Thanks in advance!
Try to use this code HTTPS working with OkHttp3 and Retrofit2
create API interface
public interface API {
#GET("/users/{user}")
Observable<Result<User>> getUser(#Path("user") String user);
}
create apiManager class which contains OKHttp3 and retrofit2 initialization and base url
public class ApiManager {
Context context;
public static final String BASE_URL = "https://api.github.com/";
private OkHttpClient okHttpClient;
private Authenticator authenticator = new Authenticator() {
#Override
public Request authenticate(Route route, Response response) {
return null;
}
};
private ApiManager() {
}
public void setAuthenticator(Authenticator authenticator) {
this.authenticator = authenticator;
}
public static class Builder {
String email, password;
ApiManager apiManager = new ApiManager();
public Builder setAuthenticator(Authenticator authenticator) {
apiManager.setAuthenticator(authenticator);
return this;
}
public ApiManager build(String param_email, String param_password) {
this.email = param_email;
this.password = param_password;
return apiManager.newInstance(email, password);
}
}
public class RequestTokenInterceptor implements Interceptor {
String email, password;
String credentials, basic;
public RequestTokenInterceptor(String email, String password) {
this.email = email;
this.password = password;
credentials = email + ":" + password;
basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
}
#Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder builder = original.newBuilder()
.addHeader("Authorization", basic)
.method(original.method(), original.body());
return chain.proceed(builder.build());
}
}
private ApiManager newInstance(String email, String password) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
#Override
public void log(String message) {
Log.i("http", message);
}
});
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
okHttpClient = new OkHttpClient.Builder()
.addInterceptor(logging)
.addInterceptor(new RequestTokenInterceptor(email, password))
.authenticator(authenticator)
.build();
return this;
}
public <T> T createRest(Class<T> t) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(okHttpClient)
.build();
return retrofit.create(t);
}
}
in Gradle add the libraries
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okhttp3:okhttp-urlconnection:3.4.1'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile 'com.squareup.okhttp3:okhttp-ws:3.4.1'
compile 'com.squareup.retrofit2:retrofit:2.0.2'
compile 'com.squareup.retrofit2:converter-gson:2.0.2'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
In MainActivity add
public class MainActivity extends AppCompatActivity {
private ProgressDialog feedbackDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
feedbackDialog = new ProgressDialog(this);
feedbackDialog.setCanceledOnTouchOutside(false);
getUser();
}
public void getUser() {
API accountAPI4 = createRestApi4();
if (accountAPI4 != null) {
showFeedback(getResources().getString(R.string.loading));
BackgroundThreadObservable.toBackground(accountAPI4.getUser("SafAmin"))
.subscribe(new Action1<Result<User>>() {
#Override
public void call(Result<User> user) {
dismissFeedback();
Log.e("GIT_HUB","Github Name :"+user.response().body().getName()+"\nWebsite :"+user.response().body().getBlog());
}
}, new Action1<Throwable>() {
#Override
public void call(Throwable throwable) {
// do something with the error
if (throwable != null) {
dismissFeedback();
}
}
}
);
} else {
dismissFeedback();
}
}
public static API createRestApi4() {
ApiManager apiManager = new ApiManager.Builder().build(email, password);
return apiManager.createRest(API.class);
}
public void showFeedback(String message) {
feedbackDialog.setMessage(message);
feedbackDialog.show();
}
public void dismissFeedback() {
feedbackDialog.dismiss();
}
}
in AndroidManifest add
<uses-permission android:name="android.permission.INTERNET"/>
Hope it helps.

Retrofit returns data but the pojo object is always empty

I'm trying to consume a service by using retrofit 2. When I call it using a web browser or log the call using an interceptor, there're some results, but my pojo classes are always empty.
The json result content is similar to:
{
"similarartists": {
"artist": [
{
"name": "Barão Vermelho",
"mbid": "84ac395b-482b-48cb-b381-b9bc420b2dd3",
"match": "1",
"url": "https://www.last.fm/music/Bar%C3%A3o+Vermelho",
"image": [],
"streamable": "0"
},
"#attr": {
"artist": "Cazuza"
}
}
}
And these are my pojo classes:
public class Similarartists {
#SerializedName("artist")
private List<Artist> artist = new ArrayList<>();
#SerializedName("attr")
private Attr attr;
}
public class Artist {
#SerializedName("name")
private String name;
#SerializedName("mbid")
private String mbid;
#SerializedName("match")
private String match;
#SerializedName("url")
private String url;
#SerializedName("image")
private List<Object> image = new ArrayList<>();
#SerializedName("streamable")
private String streamable;
}
public class Attr {
#SerializedName("artist")
private String artist;
}
The service connection class:
public class ApiService {
private static final String BASE_URL = "http://ws.audioscrobbler.com/";
public static final String API_KEY = "XXXXXXXXXX";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.connectTimeout(30, TimeUnit.SECONDS);
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
httpClient.addInterceptor(logging);
httpClient.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request original = chain.request();
// Request customization: add request headers
Request.Builder requestBuilder = original.newBuilder()
.header("Accept", "application/json")
.header("Content-Type", "application/json")
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
Retrofit retrofit = builder.client(httpClient.build()).build();
return retrofit.create(serviceClass);
}
}
Ans this is my "button" action:
private void openSearchDialog() {
ArtistService artistService = ApiService.createService(ArtistService.class);
Call<Similarartists> call = artistService.getSimilar("nirvana", ApiService.API_KEY);
call.enqueue(new Callback<Similarartists>() {
#Override
public void onResponse(Call<Similarartists> call, Response<Similarartists> response) {
if (response.isSuccessful()) {
mAdapter.setValues(response.body().getArtist());
Log.i(TAG, "onResponse: " + response.body().toString());
}
}
#Override
public void onFailure(Call<Similarartists> call, Throwable t) {
Log.e(TAG, "onFailure: ", t);
}
});
}
The problem is response.body().getArtist() is always empty. Please help me.
And this's my log result:
-01 22:51:58.844 23843-24043/com.sample.pablo.hellomusic D/OkHttp: {"similarartists":{"artist":[{"name":"Hole","mbid":"1dcc8968-f2cd-441c-beda-6270f70f2863","match":"1","url":"https://www.last.fm/music/Hole","image":[{"#text":"https://lastfm-img2.akamaized.net/i/u/34s/6687f63408074388ae703eb3905e238f.png","size":"small"},{"#text":"https://lastfm-img2.akamaized.net/i/u/64s/6687f63408074388ae703eb3905e238f.png","size":"medium"},{"#text":"https://lastfm-img2.akamaized.net/i/u/174s/6687f63408074388ae703eb3905e238f.png","size":"large"},{"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/6687f63408074388ae703eb3905e238f.png","size":"extralarge"},{"#text":"https://lastfm-img2.akamaized.net/i/u/6687f63408074388ae703eb3905e238f.png","size":"mega"},{"#text":"https://lastfm-img2.akamaized.net/i/u/arQ/6687f63408074388ae703eb3905e238f.png","size":""}],"streamable":"0"}],"#attr":{"artist":"Nirvana"}}}
Since there is a top-level key of similarartists in the response JSON I think you need another wrapper around this object, like:
public class SimilarArtistsResponse {
#SerializedName("similarartists")
private Similarartists similars;
}
And its this object you would specify in your Call<SimilarArtistsResponse>

Categories

Resources