how to retrive json object using retrofit 2 - android

I'am trying to retrieve this in my class but i got an error Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
my response from web service is {"last_question":"0","level":"0","error":"0"}
thank you
Json
{"last_question":"0","level":"0","error":"0"}
Activtiy
//calling from MainActivity
private void get()
{
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
API mApi = retrofit.create(API.class);
Call<Example> call = mApi.getdata();
call.enqueue(new Callback<Example>()
{
#Override
public void onResponse(Call<Example> call, Response<Example> response)
{
System.out.println(response.body().getError());
}
#Override
public void onFailure(Call<Example> call, Throwable t)
{
System.out.println(t.getMessage());
}
});
}
//pojo class
public class Example {
private String last_question;
private String level;
private String error;
//all getter andd setter are is here
}

Update:
Your server doesn't respond with your desired response. In fact its HTML-Code which is returned:
<html><body><script type="text/javascript" src="/aes.js" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("f655ba9d09a112d4968c63579db590b4"),b=toNumbers("98344c2eee86c3994890592585b49f80"),c=toNumbers("9cc75ba79032859c712d6ecb862cfde7");document.cookie="__test="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/"; location.href="http://advancedcalc.byethost8.com/test.php?i=2";</script><noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript></body></html>
Old (wrong) answer:
You forgot to add #SerializedName(name) Annotations to your fields within the Example class:
#SerializedName("last_question")
private String last_question;
#SerializedName("level")
private String level;
#SerializedName("error")
private String error;

Related

Read plain text response from server using Retrofit

I'm working on an application that uses Retrofit for network operations. As it stands, everything works well with GsonConverterFactory handling serialization. Here is how I setup Retrofit
Retrofit.Builder()
.baseUrl("<base url>")
.client(client)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
Now I need to connect to a legacy service which returns content in text/plain; charset=utf-8 format. Here is the Retrofit interface
#GET("https://<domain>/<endpoint>?Type=Query")
suspend fun callStatus(#Query("userId") id: Int): Response<String>
This will return status of a call for a valid user. For instance, if the user is valid and there is a status, it returns "Active" as plain text. If there is no valid user, it returns an error code of #1005
I could add custom converter factory like this (found on the web)
final class StringConverterFactory implements Converter.Factory {
private StringConverterFactory() {}
public static StringConverterFactory create() {
return new StringConverterFactory();
}
#Override
public Converter<String> get(Type type) {
Class<?> cls = (Class<?>) type;
if (String.class.isAssignableFrom(cls)) {
return new StringConverter();
}
return null;
}
private static class StringConverter implements Converter<String> {
private static final MediaType PLAIN_TEXT = MediaType.parse("text/plain; charset=UTF-8");
#Override
public String fromBody(ResponseBody body) throws IOException {
return new String(body.bytes());
}
#Override
public RequestBody toBody(String value) {
return RequestBody.create(PLAIN_TEXT, convertToBytes(value));
}
private static byte[] convertToBytes(String string) {
try {
return string.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
}
But I didn't see it make any difference. Also, it could well disguise JSON as normal text and break all existing service. Is there a better way to handle this scenario? I thought of having separate retrofit instance for plain text, bit dirty though. Do you have any other suggestions/solutions?
Edited
Response header contains the content type as
Content-Type: text/plain; charset=utf-8
Actual response for valid user
Active
Actual response for invalid user
#1005
Update
The order in which you register the converter factories matters. ScalarsConverterFactory must come first.
it should be possible by adding ScalarsConverterFactory when building the Retrofit object.
This can be done alongside with other json converters, e.g.
Retrofit.Builder()
.baseUrl("<base url>")
.client(client)
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
After that, you should be able to receive plaintext responses.
You probably need to add this to your dependencies as well:
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
The following is the way that how I get response as plain text (using Java not Kotlin).
Step One
in your gradle (Module);
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
Step Two
Create an interface
public interface MyInterface {
#GET("something.php")
Call<String> getData(#Query("id") String id,
#Query("name") String name);
}
Step Three
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.com")
.addConverterFactory(ScalarsConverterFactory.create())
.build();
MyInterface myInterface = retrofit.create(MyInterface.class);
Call<String> call = myInterface.getData("id","myname");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
String plain_text_response = response.body();
}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
});
You don't need to use a your custom implementation of Converter.Factory you could just use
// your coroutine context
val response = callStatus(userId)
if(response.isSuccessful){
val plainTextContent = response.body()
// handle plainText
} else {
//TODO: Handle error
}
//...
Two things to check first that function should not be suspended & your response should be in the Callback
No need to add extra implementation of scalars.
#GET
fun getJson(
#Url baseUrl: String = slab_pro
): Call<DataClass>

Why call have code 400 on response when postman doing it correct?

I want to provide clear code in accordance with the guidelines architecture and CleanCode rules.
I tried to use gson library to serialize data used in retrofit call.
I know that i can use #SerializedName in my model class but i want to learn how to use gson builder.
In MainActivity i have:
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
CredentialModel credentials = new CredentialModel("User", "Password");
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(credentials);
UserApiClient userApiClient = RetrofitInstace.getRetrofitInstance().create(UserApiClient.class);
Call<String> call = userApiClient.login(json);
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
toastNotify(String.valueOf(response.code()));
}
#Override
public void onFailure(Call<String> call, Throwable t) {
toastNotify("Fail");
}
});
}
});
Interface UserApiClient:
#POST("/api/AppUser/login")
Call<String> login(#Body String credentials);
RetrofitInstance class:
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(new OkHttpClient())
.build();
}
return retrofit;
}
I receive 400 error code when postman with data coppied from json variable in debug mode to body give me code 200. It isn't my serwer so i can't tell what is done on server side. Also im new in android and don't know how to check raw request in android studio yet.
You're using GsonConverterFactory.create() but you're passing String at Call<String> login(#Body String credentials); . You can't do that.
You need to pass in a POJO that is serialized by gson. Or else retrofit will pass in a null object as the body.
class MyBody {
// serialize it here
}
// You also cannot use a String at Call<String>
// for now use ResponseBody. Create a POJO class later though
Call<ResponseBody> login(#Body MyBody credentials);
What you want to do is already being done inside retrofit.
// retrofit does this for you underneat when you use GsonConverterFactory.create()
Gson gson = new GsonBuilder().serializeNulls().create();
String json = gson.toJson(credentials);

How to send post request with basic auth in retrofit?

In my code, I want to send post request with basic auth.
Here is my postman screenshot :
here is my apiInterface class
#FormUrlEncoded
#POST("GetBarcodeDetail")
Call<PreliminaryGoodsAcceptResponse> PRELIMINARY_GOODS_ACCEPT_RESPONSE_CALL(#Field("ProcName") String procName, #Field("Barcode") String barcode, #Field("LangCode") String langCode);
here is my apiclient
public class ApiClient {
public static final String BASE_URL = "http://192.**********";
private static Retrofit retrofit = null;
private static OkHttpClient sClient;
public static Retrofit getClient() {
if(sClient == null) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
sClient = new OkHttpClient.Builder()
.addInterceptor(new HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT))
.addInterceptor(interceptor)
.build();
}
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(sClient)
.build();
}
return retrofit;
}
}
My question is how can i send post request,using header :
Header Username : EBA Token :
34242353453456563DSFS
This is so far the easiest method i have ever tried for "Basic Authentication".
Use the below code to generate the auth header (API/Repository class)
var basic = Credentials.basic("YOUR_USERNAME", "YOUR_PASSWORD")
Pass this as header to the webservice call (API/Repository class)
var retrofitCall = myWebservice.getNewsFeed(basic)
Add the basic header as parameter (Retrofit Webservice interface class)
#GET("newsfeed/daily")
fun getNewsFeed(#Header("Authorization") h1:String):Call<NewsFeedResponse>
Sorry, my code is in Kotlin, but can be easily translated to Java.
References: https://mobikul.com/basic-authentication-retrofit-android/
make header like this way..
private Retrofit getClient(final Context context) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.readTimeout(60, TimeUnit.SECONDS);
client.writeTimeout(60, TimeUnit.SECONDS);
client.connectTimeout(60, TimeUnit.SECONDS);
client.addInterceptor(interceptor);
client.addInterceptor(new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (context == null) {
request = request
.newBuilder()
.build();
} else {
request = request
.newBuilder()
.addHeader("Authorization", "Bearer " + AppSetting.getStringSharedPref(context, Constants.USER_KEY_TOKEN, ""))
.build();
}
return chain.proceed(request);
}
});
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
Use Header annotation
#FormUrlEncoded
#POST("GetBarcodeDetail")
Call<PreliminaryGoodsAcceptResponse> PRELIMINARY_GOODS_ACCEPT_RESPONSE_CALL(#Header("Authorization") token: String,#Field("ProcName") String procName, #Field("Barcode") String barcode, #Field("LangCode") String langCode);
Simple-Retrofit-API-request-and-Data-Loading Here I just add the project where create the API call to access data from database using retrofit library; which is leading library to access data on network. And display the accessed data in the List format. Create the Simple Android Studio Project with Empty Activity. Create the Adapter and activity item to show normal lists in android app. Now Create the App class extending Application, as Application class is a singleton that you can access from any activity or anywhere else you have a Context object.
You can check the more details about Application class from https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class Why extend an Application class? https://developer.android.com/reference/android/app/Application.html
Add android:name=".YourApplication" i.e. class name extending the Application class in android. and class will be like public class YourApplication extends Application Init the Retrofit in Application class
//network code start
//init http logger
httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// init client client = new OkHttpClient.Builder()
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(new Interceptor() {
#Override public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Request request2 = request.newBuilder().build();
return chain.proceed(request2);
}
}).connectTimeout(30, TimeUnit.SECONDS).writeTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS).build();
Gson gson = new GsonBuilder().setLenient().create();
Retrofit mRetrofit = new Retrofit.Builder().baseUrl(Constants.API_BASE_URL).client(client).addConverterFactory(GsonConverterFactory.create(gson)).build();
mWebservice = mRetrofit.create(Webservice.class);
While Constants.API_BASE_URL is base url Create the Webervice.class where you can call the API with parameters e.g. In case of GET Method:
#GET("webservices/GetAllClientsDemoRetro.php")
Call updateChatStatus();
In case of POST method:
#FormUrlEncoded
#Headers({"Content-Type: application/x-www-form-urlencoded"})
#POST("webservices/GetAllClientsDemoRetro.php")
Call updateChatStatus();
You can See the more in details About Retrofit on Official API declaration here: http://square.github.io/retrofit/
We can parse the values with POJO i.e. Setter and Getter, using the Parceble class. Since parsing key name should be equal to the value we are receiving from the JSON response. POJO class should be declared like public class ClientData implements Parcelable { then declare the keys in the class, key values means
public class ClientData implements Parcelable
{
public String client_id;
public String company_name;
public String address_line;
public String city;
public String pincode;
public String state;
public String country;
}
Now using Alt+Enter i.e. select the option Add Parceble Implementation and press enter. Then automatically parceble class will be added. Also you have to add Setter and Getter method in class using Alt + Insert. Note: Don’t add the Setter and Getter methods for CREATER: Creater<> method If you want to use different key that JSON response key, then you should use Serialization. When I was using same key then its is like public String client_id; But when I am using the Serialization, then I can use like #Serializattion(“client_id”) public String ClientID; Now last but not a list, We call the API using retrofit, and use the response to view the Item in list-
RetroFitApplication.getWebservice().updateChatStatus().enqueue(new Callback() {
#Override public void onResponse(Call call, Response response) {
Log.d("retrofilt success", "" + response.body());
if (response.body() != null) {
clientResponceData = response.body();
Gson gson = new Gson();
String body = gson.toJson(response.body());
Log.d("retrofilt success2", "clientData" + clientResponceData.getResponse());
if (clientResponceData.getResponse() != null) {
initRV();
}
} else {
// Empty Client List Toast.makeText(ClientList.this, "Empty List", Toast.LENGTH_SHORT).show();
}
}
#Override public void onFailure(Call call, Throwable t) {
Log.d("retrofilt error", "" + t);
Toast.makeText(ClientList.this, "No Internet Connection", Toast.LENGTH_SHORT).show();
}
});
By using the Construction in Adapter, we can use the values from the response. Guys I added this repository to get the Entire idea of calling the API and get the response from server using the Retrofit Library. I write this entire documents in details with simple word.

HTTP request with Retrofit2 get "CLEARTEXT communication not supported" Error

i have a request in my Api interface:
#FormUrlEncoded
#POST(ApiStatics.authorizeURL)
Call<Oauth2Model> authorizer(#Field("grant_type") String grantType,
#Field("username") String userName,
#Field("password") String password,
#Field("client_id") String clientID,
#Field("client_secret") String clientSecret);
whit this getApi method:
public static MyAPI getApi() {
if (api == null) {
OkHttpClient client;
if (GuildsApp.isDebug()) {
HttpLoggingInterceptor bodyInterceptor = new HttpLoggingInterceptor();
bodyInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
HttpLoggingInterceptor headerInterceptor = new HttpLoggingInterceptor();
headerInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.MINUTES).writeTimeout(5, TimeUnit.MINUTES).connectTimeout(5, TimeUnit.MINUTES).addInterceptor(bodyInterceptor).addInterceptor(headerInterceptor).build();
} else {
client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.MINUTES).writeTimeout(5, TimeUnit.MINUTES).connectTimeout(5, TimeUnit.MINUTES).build();
}
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(BASE_URL);
builder.addConverterFactory(GsonConverterFactory.create());
builder.client(client);
Retrofit retrofit = builder.build();
api = retrofit.create(MyAPI.class);
}
return api;
}
i use this api in my fragment with this method:
private void login(String user, String pass) {
ApiManager.getApi().authorizer("password", user, pass, ApiStatics.CID,ApiStatics.CSecret).enqueue(new Callback<Oauth2Model>() {
#Override
public void onResponse(Call<Oauth2Model> call, Response<Oauth2Model> response) {
Log.e("authorize token",""+response.body().access_token);
}
#Override
public void onFailure(Call<Oauth2Model> call, Throwable t) {
Log.e("Failure ",""+t.getLocalizedMessage());
}
});
}
when i run project, request call onFailure method with this Log:
E/Failure: CLEARTEXT communication not supported: [ConnectionSpec(cipherSuites=[TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_2, TLS_1_1, TLS_1_0], supportsTlsExtensions=true), ConnectionSpec(cipherSuites=[TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_3DES_EDE_CBC_SHA], tlsVersions=[TLS_1_0], supportsTlsExtensions=true)]
my BASE_URL is HTTP , not HTTPS.
my login method called with login("",""); that "" are accepted on server,
how can i solve this error?
i use Retrofit 2.1.0 , my test device is nexus 5x android N
Add this annotation at the top of the class.
#PowerMockIgnore("javax.net.ssl.*")
it will ignore SSL check.
by adding a simple getApi method inside my fragment instead of ApiManager, problem solved!
private MyAPI getApi(){
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(ApiManager.BASE_URL);
builder.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
return retrofit.create(MyAPI.class);
}
and my login method now is:
private void login(String user, String pass) {
getApi().authorizer("password", user, pass, ApiStatics.CID,ApiStatics.CSecret).enqueue(new Callback<Oauth2Model>() {
#Override
public void onResponse(Call<Oauth2Model> call, Response<Oauth2Model> response) {
Log.e("authorize token",""+response.body().access_token);
}
#Override
public void onFailure(Call<Oauth2Model> call, Throwable t) {
Log.e("Failure ",""+t.getLocalizedMessage());
}
});
}
can some body explain to me what is difference between implementing getApi method in my ApiManager and in my fragment?
Try adding this to your manifest at application level
android:usesCleartextTraffic="true"
here are more details about it
CLEARTEXT communication not supported on Retrofit

How to pass POST parameter in retrofit API method?

I am writing my first code in Retrofit 1.9 version. I tried to follow several blog but not able to understand very basic problem. So far, I have created Model class using jsonschema2pojo, RestAdapter class.
Here is my model class:
#Generated("org.jsonschema2pojo")
public class GmailOauth {
#Expose
private String createdAt;
#Expose
private String objectId;
#Expose
private String sessionToken;
#Expose
private String username;
..... Getter and Setter methods...
I have created above model class using Jsonschema2pojo. So, my response JSON is very understandable.
Adapter class
public class RestApiAdapter {
public static final String BASE_URL = "http://testingserver.com:8081";
public RestAdapter providesRestAdapter(Gson gson) {
return new RestAdapter.Builder()
.setEndpoint(BASE_URL)
.build();
}
}
API class
interface GmailSignInAPI {
#POST("/signWithGmail")
void GmailOauthLogin(#Body GmailOauth user, Callback<GmailOauth> cb);
}
Now, I am confused how to write Retrofit client to pass following form-data post parameter in efficient way?
accessToken (String value)
userID (String value)
How about if I want to pass custom object in a post request and save the response of request in same object? Is this good way to do it?
I think for the api portion of Retrofit I would put
#FormUrlEncoded
#Post("/path/to/whatever")
void authenticateWithSomeCredentials(#Field("username") String userName, Callback<Object> reponse
Then I would call it like this:
public void authenticateWithSomeCredentials(username), new Callback<Object>() {
#Override
public void success(Object object, Response response) {
// Do something
}
#Override
public void failure(RetrofitError error) {
// Do something
}
}
To add the token to every call you could add an interceptor:
public class YourAuthInterceptor implements interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
request = chain.request().newBuilder()
.addHeader("token"), tokenVariable)
.build();
return chain.proceed(request);
}
}
this will add a "token" to every call you make with retrofit
so then when you build your api you build it like this
YourApi api = new RestAdapter.Builder()
.setEndpoint(url)
.setRequestInterceptor(new YourAuthInterceptor())
.build()
.create(YourApi.class);
I hope this makes sense as I am typing it rather quickly. If you have any questions please let me know.
You can do it like this:
#FormUrlEncoded
#POST("/postTosServer")
void postToServer(#Field("accessToken") String your_token, #Field("userID") String userid);

Categories

Resources