I am using retrofit with gson instead of android since its faster and more secure.
The problem is that retrofit is encoding special characters like = and ?, and the url I'm using cannot decode these characters.
This is my code:
api class:
public interface placeApi {
#GET("/{id}")
public void getFeed(#Path("id") TypedString id, Callback<PlaceModel> response);
}
Main class:
String url = "http://api.beirut.com/BeirutProfile.php?";
String next = "profileid=111";
//Creating adapter for retrofit with base url
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setRequestInterceptor(requestInterceptor).build();
//Creating service for the adapter
placeApi placeApi = restAdapter.create(placeApi.class);
placeApi.getFeed(id, new Callback<PlaceModel>() {
#Override
public void success(PlaceModel place, Response response) {
// System.out.println();
System.out.println(response.getUrl());
name.setText("Name: " + place.getName());
}
#Override
public void failure(RetrofitError error) {
System.out.println(error.getMessage());
}
});
I tried solving the problem using this gson method but it didn't work, most probably because it only includes only the first part of the url and not the one I am sending to the placeApi interface:
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
and added this when creating the restadapter:
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(url).setRequestInterceptor(requestInterceptor).setConverter(new GsonConverter(gson)).setConverter(new GsonConverter(gson)).build();
Any help please?
You must use Use #EncodedPath. like this:
public interface placeApi {
#GET("/{id}")
public void getFeed(#EncodedPath("id") TypedString id,
Callback<PlaceModel> response);
}
Note: The above works but now I am looking at the doc and it seems that the #EncodedPath is deprecated so use #PATH with its parameter instead:
public interface placeApi {
#GET("/{id}")
public void getFeed(#Path("id", encode=false) TypedString id,
Callback<PlaceModel> response);
}
ref: https://square.github.io/retrofit/2.x/retrofit/
Related
I am using a REST API created by me using SpringBoot.When I tried tested using Postman I am getting a valid JSON,but Retrofit causes this issue.
I have checked the ModelClass and it is not causing an issue.
I have other POST methods which are working absolutely fine but an issue is occuring with GET method.
The Retrofit is as follows:
public class RetrofitService {
static Gson gson = new GsonBuilder()
.setLenient()
.create();
static OkHttpClient client = new OkHttpClient();
//addConverterFactory(GsonConverterFactory.create(gson))
private static Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://Location/api/v1/")
.client(client)
//.addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
public static Retrofit createService() {
return retrofit;
}
}
The Repository is:
public class HomeFragRepository {
private Networking networking;
private MutableLiveData<EmployeeClass> mutableUserDetails;
public HomeFragRepository() {
networking= RetrofitService.createService().create(Networking.class);
}
public MutableLiveData<EmployeeClass> getUserHomeDetails(Long userId){
mutableUserDetails=new MutableLiveData<>();
networking.employeeHomeDetails(userId).enqueue(new Callback<EmployeeClass>() {
#Override
public void onResponse(Call<EmployeeClass> call, Response<EmployeeClass> response) {
if(response.isSuccessful()){
Log.i("Response",response.body().toString());
mutableUserDetails.setValue(response.body());
}
else{
try {
EmployeeClass employeeClass=new Gson().fromJson(response.errorBody().string(),
EmployeeClass.class);
Log.i("HelloLogin",employeeClass.getMessage());
mutableUserDetails.setValue(employeeClass);
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<EmployeeClass> call, Throwable t) {
t.printStackTrace();
}
});
return mutableUserDetails;
}
}
The Employee Model Class is same in Spring and Android so it is not causing any issue.
The GET Method in Spring is:
#RequestMapping(value = "/employee", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<EmployeeClass> getEmployee(#RequestParam(value="userId") Long userId){
EmployeeClass employeeClass=attendanceService.searchEmployee(userId);
return new ResponseEntity<>(employeeClass,HttpStatus.valueOf(employeeClass.getStatus()));
}
This is somehow producing a String instead of a JSON.
Thanks in Advance.
This usually happens when you're receiving something other than the expected response from the server.
It because because you mentioned EmployeeClass in Call so what happens is
the object block in your json response has no name so it is unable to find the object...
try to use
#RequestMapping(value = "/employee", method = RequestMethod.GET, produces =
MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<ResponseBody> getEmployee(#RequestParam(value="userId")
Long userId){
EmployeeClass employeeClass=attendanceService.searchEmployee(userId);
return new ResponseEntity<>
(employeeClass,HttpStatus.valueOf(employeeClass.getStatus()));
}
then parse json manually to get data and save it in your model
or you can try to add #Headers({"Accept: application/json"}) in Retrofit interface see if it works
#Headers({"Accept: application/json"})
I'm currently using Retrofit 1
I'm trying to find away to capture raw/plaintext response from server but not sure how to retrieve it.
This where i initialize it
#POST(ApplicationConstants.USER_URL+"/resendActivationEmail")
void resendEmail(#Body String email, ResponseCallback result);
and here's where i implement it.
userServiceApi.resendEmail(email, new ResponseCallback() {
#Override
public void success(Response response) {
LogHelper.debug("");
}
#Override
public void failure(RetrofitError error) {
LogHelper.debug(error.getMessage);
}
});
what i get from error.getMessage is only the http code status.
if i try to test the api with postman, this will be the response that i capture in JSON format
and this one will be in the raw/plain text format.
This is the client initialize
OkHttpClient mClient = new OkHttpClient().newBuilder().addInterceptor(new PublicApiIntercepter()).build();
return new RestAdapter.Builder()
.setEndpoint(ApplicationConstants.BASE_URL)
.setClient(new Ok3Client(mClient))
.setConverter(new GsonConverter(gson))
.setLogLevel(BuildConfig.DEBUG ? RestAdapter.LogLevel.FULL : RestAdapter.LogLevel.NONE)
.build();
Please help. thank you
Change from :
#POST(ApplicationConstants.USER_URL+"/resendActivationEmail")
void resendEmail(#Body String email, ResponseCallback result);
change to :
#POST(ApplicationConstants.USER_URL+"/resendActivationEmail")
Call<ResponseBody> resendEmail(#Body String email, ResponseCallback result);
I want to ask that do I need to create new Interfaces for every POST GET request I make which have different URL .
For ex
I made 1 interface for register and other for Login other for getting Friends. Cant I just make 1 general post and get method where I can send URL , params to send and record response?
No you don't need to create new interface or new client for each request!
Inside a interface you can create multiple method as you want and as your requirement.
For Login and fro Registration method name will be different, your parameter will not same. So you can create method as you need.
//When Base Url like "http://exmaple.com/"
#GET("Service/registration")
Call<RegResult> getRegistered(#Query("name") String name,
#Query("email") String email,
#Query("dob") String dob,
#Query("name") String name
);
#GET("Service/login")
Call<LoginResult> getLogin(#Query("username") String username,
#Query("pass") String pass
);
#GET("Service/profile")
Call<ProfileResult> getProfile(#Query("userid") String userid
);
You can also use same client because your base url is same.
If base url is diffrent you can also use same client like this..
public class ApiClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String base_url) {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(base_url)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
Now you can set different base url.
Creating object of interface...
String BASE_URL = "http://exmaple.com/";
ApiInterface apiService = ApiClient.getClient(BASE_URL).create(ApiInterface.class);
Calling method..
String user_id = "1";
Call< ProfileResult > call = apiService.getProfile(user_id);
Getting result
call.enqueue(new Callback< ProfileResult >() {
#Override
public void onResponse(Call< ProfileResult >call, Response< ProfileResult > response) {
Profile profile = response.body().getResults();
}
#Override
public void onFailure(Call< ProfileResult >call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
Hop you got your answer .... for farther query fill free to ask...
I'm trying to deserialize json from worldbank.com to a pojo without any success. The json looks like:
[{"page":1,"pages":7,"per_page":"50","total":304},[{"id":"ABW","iso2Code":"AW","name":"Aruba","region":{"id":"LCN","value":"Latin America & Caribbean "},
and can be found via: http://api.worldbank.org/countries/?format=json
and im running into problems with gson telling me:
WorldBankDemo: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 52 path $[1]
Any clues as to how i can solve this? Preferably without changing from gson since that is the lib used by the networking lib I'm using (retrofit)
WorldBankDataService service = ServiceFactory.createRetrofitService(WorldBankDataService.class, WorldBankDataService.SERVICE_ENDPOINT);
service.getCountries()
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<WorldBank[]>() {
#Override
public final void onCompleted() {
// do nothing
}
#Override
public final void onError(Throwable e) {
Log.e("WorldBankDemo", e.getMessage());
}
#Override
public final void onNext(WorldBank[] response) {
Log.d("TAG", "resp: "+response);
//mCardAdapter.addData(response);
}
});
public class ServiceFactory {
/**
* Creates a retrofit service from an arbitrary class (clazz)
* #param clazz Java interface of the retrofit service
* #param endPoint REST endpoint url
* #return retrofit service with defined endpoint
*/
public static <T> T createRetrofitService(final Class<T> clazz, final
String endPoint) {
final RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(endPoint)
.setLogLevel(RestAdapter.LogLevel.FULL)
.build();
T service = restAdapter.create(clazz);
return service;
}
}
public class WorldBank {
int page;
int pages;
String per_page;
int total;
//Country[] countrys;
}
JSON is not constructed well(especially for auto parsing), Array can contain objects or arrays but not both at same level, in the above JSON structure it starts with Array in that the first element is an object and second element is an array, so this kind of JSON structure is not recommended for auto parsing, if at all you want to continue with same JSON response you can go for manual parsing or change response structure.
It's actually a JSON array. so you can't use class. try this:
YourPojo[] objects = gson.fromJson(jsonString, YourPojo[].class)
works like a charm
try this way
Gson gson = new Gson();
String jsonOutput = "Your JSON String";
Type listType = new TypeToken<List<ApiResponse>>(){}.getType();
List<ApiResponse> posts = (List<ApiResponse>) gson.fromJson(jsonOutput, listType);
and ApiResponse is like
public class ApiResponse{
WorldBank object1;
ArrayList<Country> objects2;
}
I haven't try this on my end, but it will be similar like that.
You can use gson to customize using this dependency
compile 'org.immutables:gson:2.3.1'
But slightly different way while invoking the rest client
For instance .If we have to get a list of countries declare an interface
public interface GetAllAPI {
#GET("/all")
List<Country> getCountries();
}
Now rest client will be
public List<Country> GetAllCountries() {
Gson gson = new GsonBuilder().create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(service_url)
.setConverter(new GsonConverter(gson))
.build();
GetAllAPI service = restAdapter.create(GetAllAPI.class);
List<Country> countrylist = service.getCountries();
return countrylist;
}
Getting the results from API will be
List<Country> countrylist = service.getCountries();
You have to customize this implementation for specific requirement. This is an idea how to implement Gson with Retrofit
Go through this for more clarification
Decided to give up and use another api, the world bank api just sucks :(
I am creating a android rest client for a .net web api (MS azure). I am using jars:
retrofit 1.7.1
okhttp 2.0.0
okhttp-url-connection 2.0.0
okio 1.2.0
gson 2.3
But getting an error 500 Internal server error for POST data on server. :(
My Code is:
RestApi.java :
public interface RestApi {
#Headers({
"Accept: text/xml",
"User-Agent: REST-Client",
})
#POST("/api/Account/Register")
void sendPerson(#Body Person body, Callback<StatusData> callBack);
}
MainActivity.java
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(API_URL)
.setLogLevel(LogLevel.FULL).setLog(new AndroidLog("xx--LOG--xx"))
.build();
RestApi post = restAdapter.create(RestApi.class);
post.sendPerson(new Person(), new Callback<StatusData>() {
public void failure(RetrofitError retrofitError) {
System.out.println(retrofitError.getMessage());
}
public void success(StatusData arg0, Response arg1) {
System.out.println("barcode: " + arg0.created_at);
}
});
StatusData.java
public class StatusData {
final String status;
final String created_at;
public StatusData() {
this.status = "";
this.created_at = "";
}
}
Person.java : is just a POJO class for
name
username
password
city
address
phone
pincode
please help me???????
if your .Net server would accept only xml you should setConverter (XML Converter) on your RestAdapter. Refer http://square.github.io/retrofit/
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.soundcloud.com")
.setConverter(new SimpleXMLConverter())
.build();