I'm using Retrofit2.0 for making GET request to my REST URL. I don't need to pass any params to url for making the request.
How could on can make this type of request?
Here is my code what i 've done!
Interface ::
public interface AllRolesAPI {
#GET("/SportsApp/allroles")
Call<AllRolesParams> getAllRoles();
}
Class :::
I created a class using Pojo library it contains all the variables with setter and getter methods.
public void requestRoles() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ENDPOINT)
.build();
AllRolesAPI allRolesParams = retrofit.create(AllRolesAPI.class);
Call<AllRolesParams> allRolesParamsCall = allRolesParams.getAllRoles();
allRolesParamsCall.enqueue(new Callback<AllRolesParams>() {
#Override
public void onResponse(Call<AllRolesParams> call, Response<AllRolesParams> response) {
//response.body().getErrDesc();
Log.v("SignupActivity", "Response :: " + response.body().getErrDesc());
}
#Override
public void onFailure(Call<AllRolesParams> call, Throwable t) {
Log.v("SignupActivity", "Failure :: ");
}
});
}
When I create a request like above I have got this error in console ::
java.lang.IllegalArgumentException: Unable to create converter for class com.acknotech.kiran.navigationdrawer.AllRolesParams.
If your API's responses are JSON, you need to add
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.build();
In order to be able to use GsonConverterFactory, you need to add a gradle dependency. Check this. In your case is
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
(2.1.0 is the latest version at the time of this writing)
Quoting official docs:
By default, Retrofit can only deserialize HTTP bodies into OkHttp's
ResponseBody type and it can only accept its RequestBody type for
#Body. Converters can be added to support other types. Six sibling
modules adapt popular serialization libraries for your convenience.
Gson: com.squareup.retrofit2:converter-gson
Jackson:com.squareup.retrofit2:converter-jackson
Moshi:com.squareup.retrofit2:converter-moshi
Protobuf:com.squareup.retrofit2:converter-protobuf
Wire:com.squareup.retrofit2:converter-wire
Simple XML:com.squareup.retrofit2:converter-simplexml
Scalars (primitives, boxed,and String): com.squareup.retrofit2:converter-scalars
You are trying to parse JSON without any converter. There are various converts you can use with Retrofit. Most Popular is Gson Converter from Google. To make your code work create Retrofit adapter like this:
adapter = new Retrofit.Builder() //in your case replace adapter with Retrofit retrofit
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
Also make sure to include these dependencies:
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
Hope it works.You can refer to official retrofit docs,this guide and gson guide for more information.
Related
In my application I am using webservices using Retrofit. I have to Encrypt Field (parameter) in Request and Decrypt it on PHP Server.
I have to Encrypt and Decrypt version parameter.
Here is my RetroApi.java
public interface RetroApi {
#FormUrlEncoded
#POST("index.php/api/check-version")
Call<String> getCheckVersion(#Field("version") String version, #Field("app") String app);
}
Creating instance of RetroApi.java
RetroApi retroApi;
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().addInterceptor(logging).build();
Gson gson = new GsonBuilder().setLenient().create();
Retrofit retrofit = new Retrofit.Builder().baseUrl(RetroApp.BASE_URL).addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson)).client(httpClient).build();
retroApi = retrofit.create(RetroApi.class);
Here is the Webservice call
Call<String> getResult = retroApi.getCheckVersion(Constants.SP_APP_VERSION, Constants.SP_APP_NAME);
getResult.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
}
#Override
public void onFailure(Call<String> call, Throwable t) {
t.printStackTrace();
}
});
Please assist me to accomplish this.
Basically what you can do is simply encrypt your parameters with the standard Android tools. Here is a simple example of how to do it from which you can start.
Basically is everything you need from an Android perspective, except for a way to store a secret - for that, you can use EncryptedSharedPreferences
After that, you can send those encrypted strings as your API arguments.
you can also create a centralized encryption factory for your requests like this:
OkHttpClient okHttpClient = SomeOkHttpImplementation();
Retrofit retrofit = new Retrofit.Builder()
.client(okHttpClient)
.callFactory(new Call.Factory() {
#Override
public Call newCall(Request request) {
Request encryptedRequest = someFunctionToEncryptRequestOrItsArgs(request);
return okHttpClient.newCall(encryptedRequest);
}
})
.baseUrl(sBaseUrl)
.build();
Or with custom Interceptor as shown here
The problem is that you will have to find a way to decrypt them on PHP side. I am not a PHP expert but I'm sure there are ways to do that.
For example here and here you can find the Java and PHP implementation of the similar ciphers.
I have an Api https://hello.example.com:344/new/search/result.
Implementing same using Retrofit 2:
This is how initialising retrofit:
public static void initializeRetrofit() {
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://hello.example.com:344")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
service2 = retrofit.create(ContentService.class);
}
This is the interface request:
#POST("new/search/result")
Call<JsonObject> getSearchList(#Body JsonObject request);
But when i hit api : it removes the port from it and hits
"https://hello.example.com/new/search/result"
What is going wrong?
In your base url "https://hello.example.com:344" transform it to
"https://hello.example.com:344/"
There is no / (slash) in your base url as well as in the interface function. So the request becomes like "https://hello.example.com:344new/search/result " which will give u an error.
Add slash at the end of your base url like this "https://hello.example.com:344/"
I am calling a REST service (not mine) using retrofit which either returns a list of objects (if there are multiple) or a single object (if one). I was able to find a similar issue here however the suggestion is to change the API which i don't have control of. I also read this thread which seems to be a good approach but is there a way to handle this using Retrofit?
While the answer from #pirho seems to be applicable, I found out a different and simple solution which worked for me. Hopefully it may help others as well.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(JacksonConverterFactory.create(mapper))
.client(okHttpClient)
.build();
You can get the API response data as Map<String, JsonElement> in response and then parse it based on your requirement directly. As you can check here if JsonElement is JsonArray
for ex:
public fun parseData(val jsonElement:JsonElement){
val gson = Gson()
if(jsonElementFromServer.isJsonArray()){
//here you can just parse it into some list of array
}else{
//here you can parse using gson to single item element or model
}
}
JsonElement ref
Using Gson to get list of items or single model
As the author of the 2nd post you referred I also refer to the implementation of PostArrayOrSingleDeserializer described in that answer of mine.
When using Gson with Retrofit (Retrofit's converter-gson) you just need to register the adapter with custom Gson instance and build the Retrofit instance with that Gson instance, see below example helper class:
public class MyRetrofit {
public static MyAPI getMyApi() {
Gson gson = new GsonBuilder()
.registerTypeAdapter(Object.class,
new ObjectArrayOrSingleDeserializer())
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://example.org")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
return retrofit.create(MyAPI.class);
}
}
So the Object in the JsonDeserializer named ObjectArrayOrSingleDeserializer is the DTO you need to check for single instance or array. Replace Object with corresponding DTO and modify deserializer accordingly.
I have dynamic JSON, here is example: http://pastebin.com/QMWRZTrD
How I can parse it with Retrofit?
I failed to generate POJO classes, since I have dynamic fields like "5411" and "5412".
EDIT:
I solved it by using Map, since first value is always integer, and second is list of objects.
#FormUrlEncoded
#POST("history.php")
Observable<Map<Integer, List<Vehicle>>> getHistory(#Field("uredjaji") String vehicleId, #Field("startDate") String startDATE, #Field("endDate")
you can use Map to serialize and deserialize it in case of Random keys.
Observable<Map<Integer, List<YourObject>>>
You can get retrofit api call to return String in your RestApi Interface like
Call<String> method(#Path(..)...);
And for that to work you would need to add the scalars converter factory to where you create your Retrofit object.
First you would need to import it:
compile 'com.squareup.retrofit2:converter-scalars:2.1.0'
And then add it:
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://your.base.url/")
.build();
And then in onResponse
public void onResponse(Call<String> call, Response<String> response) {
if (response.isSuccessful()) {
Type mapType = new TypeToken<Map<String,List<SomeClass>>() {}.getType(); // define generic type
Map<String,List<SomeClass>> result= gson.fromJson(response.body(), mapType);
} else {
}
}
Also,check out this site it has great tutorials on Retrofit.
I'm using retrofit to call a web service and retrofit is throwing a failure, the the message from the 'Throwable` is giving me
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path $
I'm assuming that this is because the .Net web service is throwing an error and not returning JSON. But to prove this I need to be able to see the raw response in the onFailure. Is there anyway I can do this?
this is the code I'm using
public void userLoginRequestEvent(final AuthenticateUserEvent event) {
Call call = sApi.login(event.getUsername(), event.getPassword(), OS_TYPE, DeviceInfoUtils.getDeviceName());
call.enqueue(new Callback<LoggedInUser>() {
#Override
public void onResponse(Response<LoggedInUser> response, Retrofit retrofit) {
// response.isSuccess() is true if the response code is 2xx
if (response.isSuccess()) {
LoggedInUser user = response.body();
AppBus.getInstance()
.post(new UserIsAuthenticatedEvent(user, event.getUsername(),
event.getPassword()));
} else {
int statusCode = response.code();
// handle request errors yourself
}
}
#Override
public void onFailure(Throwable t) {
// handle execution failures like no internet connectivity
Log.d("ERROR", t.getMessage());
}
});
You can use the log interceptor that exists in the okhttp-logging-interceptor.
A good example can be found in Logging with Retrofit 2 as well.
Your server answer is just a string, not an object. Use an Interceptor to see your received response.
Add incerceptor dependency
compile 'com.squareup.okhttp3:logging-interceptor:3.4.0'
and then add it to your custom OkHttp client.
OKHttp client = ....
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
client.interceptors().add(interceptor);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("url")
.client(client) // add custom OkHttp client
You can check for BASIC, HEADERS and BODY. In your case you check for BODY to see body that you send and what server is sending as response body.