I have some custom POJO:
class CustomClass {
int x;
String str;
SecondCustomClass obj; //indicate it's not class of simple types
//etc...
}
I want to send instance of him from Android (Volley library) client to web service running on Spring-boot java application. Currently I know how to send data with URL params and return to client custom object. But I want also to send custom object.
Code in Android (I know that I need to use 3'rd parameter which is now null but I'm struggling get it work):
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET,
"BASE_URL?param1=param",
null,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
CustomClass result = new Gson().fromJson(response.toString(), CustomClass.class);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}
);
volleyQueue.add(request);
Code in server:
EDIT: The solution to receive pojo is using #RequestBody
#RequestMapping("/webmethod")
public CustomClass webmethod(#RequestParam(value="obj_param") #RequestBody CustomClass obj) {
//work with obj
}
What do I need to put in Android side to get it work?
You have to use the JSON object inside the JSON object.Below is the sample. When you are request the Parameter with only one request.
This the Request JSON
{
"x":10,
"str":"MyName",
"SecondCustomClass":{
"id":10,
"title":"make it eassy"
}
}
This is the post parameter request from Android. Try this way.
For more details please use this link
Related
I am using retrofit to retrieve login JSON result from server for that i need to post user name and password. I have tried this code but i get response saying invalid Web Service. but i get correct response using Rest.
My code is something like this,
MainActivity.java
String url = "http://***.***.in/***/******/*********/UserService.php?request=Verify_User_Credential";
//making object of RestAdapter
RestAdapter adapter = new RestAdapter.Builder().setEndpoint(url).build();
//Creating Rest Services
RestInterface restInterface = adapter.create(RestInterface.class);
//Calling method to get login report
restInterface.getLoginReport(username, password, new Callback<Model>()
{
#Override
public void success(final Model model, Response response) {
if (RetailConnectUtils.isSuccess(model.getStatus())) {
runOnUiThread(new Runnable() {
#Override
public void run() {
// retrieve status and message from model and display
}
});
}
});
RestInterface::
#FormUrlEncoded
#POST("/GetData")
void getLoginReport(#Field("username")String uname,#Field("password")String password,Callback<Model> cb);
and POJO class model containing json converted values It contain method getStatus and getMessage...
Here what should i mention in #POST("******").. is that webservice method or default retrofit method?
I'm going to develop a small-sized system to raise my developing skills.
It consists of the three parts listed below:
1. Web DB
2. Web Page
3. Android App
The main feature is managing the members. (login, just showing the user information)
At this point, I'm wondering about the android app part.
Especially, the HTTP.
I found two libraries which are JSoup and Retrofit.
As far as I can tell, those libraries are a little bit different.
I think the retrofit is a better fit for me...
Up until now I couldn't find a good sample...
Can you give me a hint how to do this?
If you are trying to connect to a Web Database I would suggest using Volley which is really simple and straightforward and really powerful yet: https://developer.android.com/training/volley/index.html.
Here's an example on how you could set your query with volley from the android developer site:
final TextView mTextView = (TextView) findViewById(R.id.text);
...
// Instantiate the RequestQueue.
RequestQueue queue = Volley.newRequestQueue(this);
String url ="http://www.google.com";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
mTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
mTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
Retrofit example
Synchronous
Interface
public interface RestApi {
#POST("/Login")
String login(#Body User user);
}
Simple class which follows the singleton design pattern
public class RestClient {
private static RestApi API_INSTANCE;
private static final String ENDPOINT = "http://192.168.6.99:50500/Phone";
static {
setUpHttpClient();
}
private static void setUpHttpClient() {
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(ENDPOINT)
.setLogLevel(BuildConfig.DEBUG ?
RestAdapter.LogLevel.FULL :
RestAdapter.LogLevel.NONE)
.build();
API_INSTANCE = restAdapter.create(RestApi.class);
}
private RestClient() {}
public static RestApi getApiInstance() {
return API_INSTANCE;
}
}
Call it for example in an IntentService
String userToken = "";
try {
// post to http://192.168.6.99:50500/Phone/Login
userToken = RestClient.getApiInstance().login(new User(login, password));
} catch (RetrofitError error) {
//...
}
build.gradle
compile 'com.squareup.retrofit:retrofit:1.9.0'
Or Asynchronous
interface
public interface RestApi {
#POST("/Login")
void login(#Body User user, Callback<String> token);
}
and do the request with a callback..
Preface: I'm using Retrofit to handle my API calls and Realm(realm.io) to store the data.
The API im dealing with uses the following structure:
Array Response
{
"response":
[
{
"objectField1":"abc"
"objectField2":"abc"
"objectField3":"abc"
"objectField4":"abc"
},
{
"objectField1":"abc"
"objectField2":"abc"
"objectField3":"abc"
"objectField4":"abc"
}
]
}
Single object response
{
"response":
{
"objectField1":"abc"
"objectField2":"abc"
"objectField3":"abc"
"objectField4":"abc"
}
}
All api responses are contained in a response object either in an array (if result size > 1) or an object (if result size == 1).
I currently have my API call as follows:
#GET("/api/myEndpoint")
void getAllExampleObjects(Callback<MyRealmClass> callback);
How can I serialise the API response (handling both array and single object cases) to place them in my realm?
Christian from Realm here.
If you have a single REST API call that can return both a list and a single object, you will have to do something manually. As colriot points out you will have to write your own GSON deserializer. For ideas how to write one see a very good answer in this SO post: How to handle parameters that can be an ARRAY or OBJECT in Retrofit on Android?
To get the objects into Realm you can use realm.copyToRealm(objects) in the following way:
#GET("/api/myEndpoint")
void getAllExampleObjects(Callback<List<MyRealmClass>> callback);
Callback callback = new Callback() {
#Override
public void success(List<MyRealmClass> objects, Response response) {
realm.beginTransaction();
realm.copyToRealm(objects);
realm.commitTransaction();
}
#Override
public void failure(RetrofitError retrofitError) {
}
};
The REST Api I'm working with has custom codes and messages which are sent from server depending on the state, I would like to implement a custom Callback<T> that calls the success method only if the status code was 0.
Example SUCCESS Response received from server:
{
"code":"0",
"message":"success",
"data": {
"actual_data":"goes_here",
"need_to_construct_objects","from_data"
}
}
Example of FAILURE Response:
{
"code":"301",
"message":"wrong_password",
"data": {
"actual_data":"will_be_null",
"no_need_to_construct_objects","from_data"
}
}
code and message are returned by all requests, the data contains the actual response values, so I would like to do the following:
Check the code and message and only call success() if code is 0.
Call failure() if request failed or code != 0
Construct custom objects based on the data response and pass them via success()
What is the best way to do this? I searched everywhere and could not find a good solution. The only one I got was to let all custom objects have the code and message fields too and check their values inside success(), but this could cause problems in future in case someone forgets to check the code before proceeding.
You can do that quickly by just making an abstract class that implements Callback, and declare your own abstract success and failure methods. The abstract class will handle Retrofit's standard callback methods, interpret the response and call the abstract methods accordingly.
I think another possible approach to this is to override Retrofit's Client interface to build your own Response object.
If you extend OkClient, it can go like this:
public class CustomClient extends OkClient {
#Override public Response execute(Request request) throws IOException {
Response originalRespone = super.execute(request);
int statusCode = 0;
//TODO: read JSON response here (using GSON or similar, and extract status code and message... etc.)
//Convert the status code to HTTP standard status codes, according to the documentation you have.
if(statusCode == 0) statusCode = 200;
//Reconstruct a Response object
return new Response(originalResponse.getUrl(), statusCode, originalResponse.getReason() /*should probably replace with parsed message*/, originalResponse.getHeaders(), originalResponse.getBody());
}
This may be more work than handling your case in Callback, but I think it can help if at some point the API transitions to RESTful API conventions.
This solution comes with its own problem though, because that means the JSON conversion will run twice. One in your client, and another one by Retrofit. Not sure the correct way to do that at the moment. Probably something around TypedInput and a dummy Converter that passes already converted objects.
Create a custom ResponseBodyConverter like this:
public class CustomResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private final TypeAdapter<T> adapter;
CustomResponseBodyConverter(TypeAdapter<T> adapter) {
this.adapter = adapter;
}
#Override
public T convert(ResponseBody value) throws IOException,CustomException {
String json = "";
try {
String body = value.string();
json = new JSONObject(body).getJSONObject("data").toString();
int code = new JSONObject(body).getInt("code");
String message = new JSONObject(body).getString("message");
if(code != 0){
throw new CustomException(message);
}
} catch (JSONException e) {
e.printStackTrace();
}
return adapter.fromJson(json);
}
}
It's a better idea to implement a custom callback. You can an example about it below.
public abstract class DefaultRequestCallback<T> implements Callback<T> {
public abstract void failure(Meta meta);
public abstract void success(T responseBean);
#Override
public void success(T baseResponseBean, Response response) {
// You can check your responsebean's error code and
// convert it to a default error
BaseResponseBean bean = (BaseResponseBean) baseResponseBean;
if (bean == null) {
failure(new Meta(ApplicationConstants.ERROR_RETROFIT, "Unknown Error!"));
} else if (bean.getMeta() != null && bean.getMeta().getCode() != ApplicationConstants.RESULT_SUCCESS) {
failure(bean.getMeta());
} else {
success(baseResponseBean);
}
}
#Override
public void failure(RetrofitError error) {
// Convert default error to your custom error.
Meta meta = new Meta(ApplicationConstants.ERROR_RETROFIT, "Error Unknwon");
failure(meta);
}
}
Give your custom callback to your retrofit service interface method.
void yourMethod(DefaultRequestCallback<YourResponseBean> callback);
Good Luck.
This will at least get you started. You can basically create your own custom callback and then handle the success. Look at what was sent and do what you need to.
public class CustomCallback implements Callback {
#Override
public void success(Object o, Response response) {
//Check for success
//if( Success )
//callback.success(o, response);
//else
//Check for error
//callback.failure(error);
}
}
In your case, you can have a class that maps your json response:
class CustomResponse {
String code;
String message;
Data data;
static class Data {
String actualData;
String needToContructObjects;
String noNeedToContructObjects;
}
}
Then, since you're back to the java objects world, you can have a factory-like object inside your success method callback that creates the desired object based on the returned custom response. If you want to get this response in the failure callback, I'd reconsider using Retrofit, since your API is not following a good Rest design.
Although this is plenty possible, and understanding you might not be involved on the API development, be aware this is not a good API design approach. If you are POSTing a login request to the server, you can understand this request as a request to create a resource (an authenticated user session, for instance). If you don't send the correct parameters (the correct username and password in this specific case), the server should reject the resource creation request and send back a 4-hundred-something (4xx) http status code indicating your request was not correct somehow. Retrofit would understand this 4xx status code and call your failure callback, where you could handle the response appropriately.
I have an auth REST api that returns the following JSON response (I am following http://jsonapi.org convention)
{ "user" : { "id" : 1, "first_name" : "Jack" } }
I noticed that Retrofit/Gson does not parse out the root user object automagically? so instead of giving a User object in my success callback, I am doing the following, was wondering if theres a better way to do this? I am new to Retrofit/Android.
authService.signIn(authJson, new Callback<JsonObject>() {
#Override
public void success(JsonObject jsonObject, Response response) {
User user = new Gson().fromJson(jsonObject.get("user"), User.class);
progress.hide();
signInSuccess(user);
}
#Override
public void failure(RetrofitError retrofitError) {
}
});
I think you should just create a wrapping class like that:
class UserWrapper {
User user;
}
and make that the return type of the Retrofit interface.
There's an issue with your solution as well. If I remember correctly, Retrofit streams the network data directly to Gson on the fly. Your solution, on the other hand, will parse User object after the full response is received, and on the main thread as well.
The penalty may not be that significant for a single request, but it's something you'd probably want to avoid for general optimization.
You can write your own deserializer, register it in GsonBuilder and pass it to the RestAdapter
Registering Type:
GsonBuilder gb = new GsonBuilder();
gb.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
gb.registerTypeAdapter(User.class, new UserDeserializerDeserializer());
OkClient okClient = new OkClient();
Builder restAdapter = new RestAdapter.Builder();
restAdapter.setEndpoint(BASE_URL);
restAdapter.setExecutors(Executors.newCachedThreadPool(), new MainThreadExecutor());
restAdapter.setConverter(new GsonConverter(gb.create()));
mRestAdapter = restAdapter.build();//
UserDeserializer class:
public class UserDeserializer implements JsonDeserializer<User>{
private static Gson sGson = new Gson();
#Override
public User deserialize(JsonElement arg0, Type arg1,
JsonDeserializationContext arg2) throws JsonParseException {
JsonObject userObject = arg0.getAsJsonObject().getAsJsonObject("user");
return sGson.fromJson(userObject, arg1);
}
You are deserializing the response in the success method, which could hang the UI (under assumption you are using MainThreadExecutor for callbacks) in the cases where you have huge huge response.
Approach with writing your own deserializer will parse the response on the background thread too.