Spring-MVC & Android: Server gets a empty JSON string from android - java

I am working on an Android project in which I want to create a RESTful POST connection to a Spring-MVC based server. I initially tried to post an object but I used to get errors. That is why I tried to send a JSON object. Currently I don't get any errors in the Android app, but when I receive the JSON object and get the String, there is nothing in the JSON object.
I debugged the code to see that values are being sent correctly. I don't know what I am doing wrong. Any help would be nice. Thanks a lot.
Android code to send object :
#Override
public void addRestaurant(Restaurant restaurant) {
Log.d("Restaurant Name",restaurant.getRestaurantName());
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
Looper.prepare();
HttpClient client = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(client.getParams(),10000);
HttpResponse response;
JSONObject jsonObject = new JSONObject();
HttpPost post = new HttpPost(url);
jsonObject.put("restaurantName",restaurant.getRestaurantName());
jsonObject.put("postLeitZahl",restaurant.getPostLeitZahl());
jsonObject.put("phoneNumber",restaurant.getPhoneNumber());
jsonObject.put("id",restaurant.getId());
StringEntity stringEntity = new StringEntity(jsonObject.toString());
stringEntity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE,"application/JSON"));
post.setEntity(stringEntity);
response = client.execute(post);
} catch (Exception e){
e.printStackTrace();
}
Looper.loop();
//String response = restTemplate.postForObject(url,restaurant,String.class);
//Log.d(response,"Response from webserver is");
}
});
thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
}
}
Spring Controller code :
#RequestMapping(value = "/restaurant/add",method = RequestMethod.POST,consumes="application/json")
#ResponseBody
public String addRestaurantWebView(JsonObject restaurant){
System.out.println(restaurant.getAsString());
return "true";
}
I don't know what I am doing wrong and I am having trouble finding some resources which can tell me how to configure the server according to the code in android or vice-versa. Thanks a lot ..:-)
Edit (Solution)(Partial with Java Objects)
As my original intention was to send a Java object which was failing, I reverted to JSON, but later it worked with Java, here is the Android code and the Spring-MVC Controller and bean which worked for me.
Android code :
package com.example.myapp;
import android.os.Process;
import android.util.Log;
import org.springframework.http.*;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
public class RestaurantServiceImpl implements RestaurantService {
String url = "http://192.168.178.40:8080/restaurant/add";
#Override
public void addRestaurant(Restaurant restaurant) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity entity = new HttpEntity(restaurant,headers);
ResponseEntity<String> out = restTemplate.exchange(url, HttpMethod.POST,entity,String.class);
Log.d(out.toString(),"Response from server");
} catch (Exception e){
e.printStackTrace();
}
}
});
thread.setPriority(Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
}
}
Spring-MVC controller :
#RequestMapping(value = "/restaurant/add",method = RequestMethod.POST)
#ResponseBody
public String addRestaurantWebView(#RequestBody Restaurant restaurant){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("restaurant", new Restaurant());
modelAndView.addObject(restaurant);
this.restaurantService.addRestaurant(restaurant);
return "true";
}
Servlet-context.xml
Add this :
<mvc:annotation-driven />
<beans:bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<beans:ref bean="jsonMessageConverter"/>
</beans:property>
</beans:bean>
<beans:bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>

This is how I would do: create the class Restaurant on you're Spring app. Then use it as the parameter in the request mapping with #ModelAttribute:
public String addRestaurantWebView(#ModelAttribute Restaurant restaurant) {
Then, on Android send the parameters with a MultipartEntity:
Charset charset = Charset.forName("UTF-8");
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, null, charset);
entity.addPart("restaurantName", new StringBody(restaurant.getRestaurantName(), charset));
entity.addPart("postLeitZahl", new StringBody(restaurant.getPostLeitZahl(), charset));
entity.addPart("phoneNumber", new StringBody(restaurant.getPhoneNumber(), charset));
entity.addPart("id", new StringBody(restaurant.getId(), charset));
HttpPost post = new HttpPost(url);
post.setEntity(entity);
response = client.execute(post);

Related

How to fix ServerCode 302 with my restful springboot server

I just made a new Springboot Project and every time I want so implement the Controller for the Mapping from my API into my Database I get the statuscode 302.
The class I want to put into the db is a Movie, here is the Moviecontroller
#RestController()
#RequestMapping(path = "movie")
public class MovieController {
private final MovieService movieService;
#Autowired
public MovieController(MovieService movieService){ this.movieService = movieService; }
#GetMapping("getmovie")
public List<Movie> getMovie(){
return movieService.getMovie();
}
#PostMapping(path = "postmovie")
public void addNewMovie(#RequestBody Movie movie){
movieService.addNewMovie(movie);
}
}
The Class which handles the API has this method in it which is supposed to handle a Movie Json and send it via http to the Controller. Since I want to post the minimum code necessary for this Problem I do not post the complete class. The Route is...
#Route(value = "addmovie", layout = MainLayout.class)
public void saveMovieInDatabase(int movieId, String title, String posterSrc, int releaseDate,int length) throws IOException {
String movieString = new ObjectMapper().writeValueAsString(new Movie(movieId,title,posterSrc,releaseDate,length));
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost("http://localhost:8080/movie/postmovie");
post.setEntity(new StringEntity(movieString));
post.setHeader("Accept","application/json");
post.setHeader("Content-type", "application/json");
CloseableHttpResponse response = client.execute(post);
System.out.println(response.getStatusLine().getStatusCode());
}

I cannot send an HTTP request (500 internal server error)

I am currently receiving the following error for the http request am sending. I am trying to send a JSON Array list to trigger a method in the receiving end so as it saves the list in its database.
The 500 Internal Server Error is a very general HTTP status code that means something has gone wrong on the website's server, but the server could not be more specific on what the exact problem is.
Websites phrase 500 errors in many ways but they're all basically saying the same thing: there's a general server issue going on right now.
Most of the time there isn't anything you can do but contact the website directly and then wait on them to fix it.
In the off chance there is a problem on your end, try clearing the cache and deleting any cookies from the site with the error.
Please find the error below:
org.springframework.web.client.HttpServerErrorException: 500 Internal Server
public static String FRONT_URL;
public static String BACK_URL;
public static final String REST_SYNC = "rest/sync";
public static final String REST_API = "rest/api";
private Logger log = Logger.getLogger(FrontSynchronizer.class);
static final Logger synclog = Logger.getLogger("sync");
ResourceBundle rb = ResourceBundle.getBundle("bundles.sync-application-resources", Locale.getDefault());
//method sending the request
public void syncApplications(List<SchemeApplication> accList) {
schemeApplicationDto=new SchemeApplicationDto();
FRONT_URL = rb.getString("sync.front.url").concat(REST_SYNC);
BACK_URL = rb.getString("sync.back.url").concat(REST_API);
JSONArray array = new JSONArray();
if (accList != null && accList.size() > 0) {
for (SchemeApplication student : accList) {
schemeApplicationDto.setId(student.getId());
schemeApplicationDto.setAccountID(student.getAccountID());
schemeApplicationDto.setNoOfPersonsEmployedLocal(student.getNoOfPersonsEmployedLocal());
schemeApplicationDto.setLocalmainclients(student.getLocalmainclients());
JSONObject studentJSON = new JSONObject(schemeApplicationDto);
array.put(studentJSON);
}
}
HttpHeaders headers = new HttpHeaders();
JSONObject object = new JSONObject();
object.put("array", array);
headers.setContentType(MediaType.APPLICATION_JSON);
RestTemplate restTemplate = this.createnewTemplate();
String url = BACK_URL.concat("/application");
HttpEntity<String> requestEntity = new HttpEntity<String>(object.toString(), headers);
ResponseEntity<Boolean> responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity,
Boolean.class);
if (responseEntity.getBody())
{
for(SchemeApplication scheme:accList) {
schemeApplicationService.getDao().delete(scheme);
}
}
}
public RestTemplate createnewTemplate() {
// RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectTimeout(120000);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
return restTemplate;
}
// method that needs to process the request
//The method is trying to send an Array list so as the receiving end can receive the list and save it in its database.
#RequestMapping(value = "application", method = RequestMethod.POST)
public Boolean getAllArchivedpplications(#RequestBody String schemeJson) {
List<SchemeApplication> accList = null;
try {
accList = new ArrayList<SchemeApplication>();
if (StringUtils.isNotEmpty(schemeJson)) {
JSONObject listObject = new JSONObject(schemeJson);
JSONArray entryArray = listObject.getJSONArray("array");
for (int i = 0; i < entryArray.length(); i++) {
JSONObject res = new JSONObject(entryArray.get(i).toString());
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
schemeApplication doc = mapper.readValue(res.toString(),
new TypeReference<schemeApplication>() {
});
accList.add(doc);
}
schemeService.getDao().save(accList); // Service.save accountlist;
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
#RequestBody must work on an object.
Standard way to do this kind of work in two ways:
Form a class having class files with same name and structure with your json data you are sending and capture that data in by #RequestBody annotation
As you are sending data as String, send it as request param, and use #RequestParam instead of #RequestBody and parse the way you need to do things. For I think for this kind of arrayList of bulk data you are working with, option 1 will be better/feasible.
For details you can check here: #RequestBody and #ResponseBody annotations in Spring

Working on the aws lambda by using the aws proxy response but it's not showing the Gzipped response at client side

I have created the Example Handler with AwsproxyRequest and response.
I am trying to zip this response with gzipping but in browser it is failing.
If I have added this same response in nodejs it is working fine.
public class ExampleHandler1 implements RequestHandler<AwsProxyRequest,AwsProxyResponse> {
#Override
public AwsProxyResponse handleRequest(AwsProxyRequest input, Context context) {
AwsProxyResponse response = new AwsProxyResponse(200, Collections.singletonMap("X-Powered-By", "AWS Lambda & serverless"), "Aaytu");
try {
HashMap<String, String> headermap = new HashMap<>();
headermap.put("Content-Encoding", "gzip");
headermap.put("Content-Type", "text/html");
String responseString = Base64.getMimeEncoder().encodeToString(GzipCompressor.compress("Hello there..!!!").getBytes());
AwsProxyResponse retVal = new AwsProxyResponse(200, headermap, responseString);
retVal.setBase64Encoded(true);
return retVal;
} catch (Exception e) {
}
return response;
}
}

Sending file over spring rest service via resttemplate

Title might look common but none of them fit in my issue.
I have a rest service which accept normal parameters and file in form of multipart.
i want to use resttemplate to send data and file to above rest service.
till the time i was sending normal string data there was no issue. once i add code of sending bytes then i start getting 400 Bad request error.
if i comment code to send ByteArrayResource then it start working for normal parameters.
below is sample code
Rest service controller
#RestController
#RequestMapping(value="/ticket")
public class UserTicketController {
#RequestMapping(value="/createTicket.do",method={RequestMethod.POST},
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE},headers={"content-type="+MediaType.MULTIPART_FORM_DATA_VALUE})
public void createTicket(#ModelAttribute ServiceDeskRequest serviceDeskRequest, HttpServletRequest request,HttpServletResponse response) throws Exception{
}
}
Servicedeskrequest model attribute is
public class ServiceDeskRequest implements Serializable{
private String jsonData;
private MultipartFile attachment;
}
application-context.xml
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
Client Side code
RestTemplate restTemplate = new RestTemplate();
MultiValueMap<String, Object> requestParamerterMap = new LinkedMultiValueMap<String, Object>();
requestParamerterMap.add("jsonData", jsonData);
MultipartFile attachment = userRequest.getAttachment();
if(attachment!=null && attachment.getOriginalFilename()!=null) {
ByteArrayResource byteArrayResource = new ByteArrayResource(attachment.getBytes(), attachment.getOriginalFilename());
requestParamerterMap.add("attachment", byteArrayResource);
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParamerterMap, headers);
String response = restTemplate.postForObject(targetUrl, requestEntity, String.class);
I figured it out. There are two piece in this puzzle. No change in service code.
Providing right converter to resttemplate. In list of default converts spring doesn't add FormHttpMessageConverter.
FormHttpMessageConverter converter = new FormHttpMessageConverter();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(converter);
overriding bytearrayresource class. plz note you need to override getFilename method so that document name can be received at service side.
public class MultipartByteArrayResource extends ByteArrayResource{
private String fileName;
public MultipartByteArrayResource(byte[] byteArray) {
super(byteArray);
}
public String getFilename() {
return fileName;
}
public void setFilename(String fileName) {
this.fileName= fileName;
}
}
After above changes client code will be
FormHttpMessageConverter converter = new FormHttpMessageConverter();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(converter);
MultiValueMap<String, Object> requestParamerterMap = new LinkedMultiValueMap<String, Object>();
requestParamerterMap.add("jsonData", jsonData);
MultipartFile attachment = userRequest.getAttachment();
if(attachment!=null && attachment.getOriginalFilename()!=null) {
//ByteArrayResource byteArrayResource = new ByteArrayResource(attachment.getBytes(), attachment.getOriginalFilename());
MultipartByteArrayResource resource = new MultipartByteArrayResource(attachment.getBytes());
//pass file name sepratly
resource.setFilename(attachment.getOriginalFilename());
requestParamerterMap.add("attachment", resource);
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>(requestParamerterMap, headers);
String response = restTemplate.postForObject(targetUrls.get("sdCreateTicketsUrl"), requestEntity, String.class);
First, value="/createTicket.do" is way off the REST convention. Same goes for /ticket.
Creation of a ticket should be done by POST to URL: .../tickets/

How to call a RESTful web service from Android?

I have written a REST web service in Netbean IDE using Jersey Framework and Java.
For every request the user needs to provide a username and a password, I know that this authentication is not a best practice (using a curl command like: curl -u username:password -X PUT http://localhsot:8080/user).
Now I want to call a REST web service from an Android Class.
How should I do it?
I have an Android Class which uses DefaultHttpClient and CredentialUsernameAndPassword, but when I run it in Eclipse, sometimes I get a runtime exception or SDK exception.
This is an sample restclient class
public class RestClient
{
public enum RequestMethod
{
GET,
POST
}
public int responseCode=0;
public String message;
public String response;
public void Execute(RequestMethod method,String url,ArrayList<NameValuePair> headers,ArrayList<NameValuePair> params) throws Exception
{
switch (method)
{
case GET:
{
// add parameters
String combinedParams = "";
if (params!=null)
{
combinedParams += "?";
for (NameValuePair p : params)
{
String paramString = p.getName() + "=" + URLEncoder.encode(p.getValue(),"UTF-8");
if (combinedParams.length() > 1)
combinedParams += "&" + paramString;
else
combinedParams += paramString;
}
}
HttpGet request = new HttpGet(url + combinedParams);
// add headers
if (headers!=null)
{
headers=addCommonHeaderField(headers);
for (NameValuePair h : headers)
request.addHeader(h.getName(), h.getValue());
}
executeRequest(request, url);
break;
}
case POST:
{
HttpPost request = new HttpPost(url);
// add headers
if (headers!=null)
{
headers=addCommonHeaderField(headers);
for (NameValuePair h : headers)
request.addHeader(h.getName(), h.getValue());
}
if (params!=null)
request.setEntity(new UrlEncodedFormEntity(params, HTTP.UTF_8));
executeRequest(request, url);
break;
}
}
}
private ArrayList<NameValuePair> addCommonHeaderField(ArrayList<NameValuePair> _header)
{
_header.add(new BasicNameValuePair("Content-Type","application/x-www-form-urlencoded"));
return _header;
}
private void executeRequest(HttpUriRequest request, String url)
{
HttpClient client = new DefaultHttpClient();
HttpResponse httpResponse;
try
{
httpResponse = client.execute(request);
responseCode = httpResponse.getStatusLine().getStatusCode();
message = httpResponse.getStatusLine().getReasonPhrase();
HttpEntity entity = httpResponse.getEntity();
if (entity != null)
{
InputStream instream = entity.getContent();
response = convertStreamToString(instream);
instream.close();
}
}
catch (Exception e)
{ }
}
private static String convertStreamToString(InputStream is)
{
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
try
{
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
is.close();
}
catch (IOException e)
{ }
return sb.toString();
}
}
Recently discovered that a third party library - Square Retrofit can do the job very well.
Defining REST endpoint
public interface GitHubService {
#GET("/users/{user}/repos")
List<Repo> listRepos(#Path("user") String user,Callback<List<User>> cb);
}
Getting the concrete service
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.build();
GitHubService service = restAdapter.create(GitHubService.class);
Calling the REST endpoint
List<Repo> repos = service.listRepos("octocat",new Callback<List<User>>() {
#Override
public void failure(final RetrofitError error) {
android.util.Log.i("example", "Error, body: " + error.getBody().toString());
}
#Override
public void success(List<User> users, Response response) {
// Do something with the List of Users object returned
// you may populate your adapter here
}
});
The library handles the json serialization and deserailization for you. You may customize the serialization and deserialization too.
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Date.class, new DateTypeAdapter())
.create();
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint("https://api.github.com")
.setConverter(new GsonConverter(gson))
.build();
Stop with whatever you were doing ! :)
Implement the RESTful client as a SERVICE and delegate the intensive network stuff to activity independent component: a SERVICE.
Watch this insightful video
http://www.youtube.com/watch?v=xHXn3Kg2IQE where Virgil Dobjanschi is explaining his approach(es) to this challenge...
Using Spring for Android with RestTemplate
https://spring.io/guides/gs/consuming-rest-android/
// The connection URL
String url = "https://ajax.googleapis.com/ajax/" +
"services/search/web?v=1.0&q={query}";
// Create a new RestTemplate instance
RestTemplate restTemplate = new RestTemplate();
// Add the String message converter
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
// Make the HTTP GET request, marshaling the response to a String
String result = restTemplate.getForObject(url, String.class, "Android");
I used OkHttpClient to call restful web service. It's very simple.
OkHttpClient httpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.build();
Response response = httpClient.newCall(request).execute();
String body = response.body().string()
What back-end? If JAVA then you can use REST with Java (JAX-RS) using Jersey.
On the Android side you can use this simple RestClient to work with that REST service.
For JSON <--> Object mapping on both sides (Android, Java back-end) you can use GSON.
Perhaps am late or maybe you've already used it before but there is another one called ksoap and its pretty amazing.. It also includes timeouts and can parse any SOAP based webservice efficiently. I also made a few changes to suit my parsing.. Look it up
Follow the below steps to consume RestFul in android.
Step1
Create a android blank project.
Step2
Need internet access permission. write the below code in AndroidManifest.xml file.
<uses-permission android:name="android.permission.INTERNET">
</uses-permission>
Step3
Need RestFul url which is running in another server or same machine.
Step4
Make a RestFul Client which will extends AsyncTask. See RestFulPost.java.
Step5
Make DTO class for RestFull Request and Response.
RestFulPost.java
package javaant.com.consuming_restful.restclient;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.util.Log;
import com.google.gson.Gson;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.util.Map;
import javaant.com.consuming_restful.util.Util;
/**
* Created by Nirmal Dhara on 29-10-2015.
*/
public class RestFulPost extends AsyncTask<map, void,="" string=""> {
RestFulResult restFulResult = null;
ProgressDialog Asycdialog;
String msg;
String task;
public RestFulPost(RestFulResult restFulResult, Context context, String msg,String task) {
this.restFulResult = restFulResult;
this.task=task;
this.msg = msg;
Asycdialog = new ProgressDialog(context);
}
#Override
protected String doInBackground(Map... params) {
String responseStr = null;
Object dataMap = null;
HttpPost httpost = new HttpPost(params[0].get("url").toString());
try {
dataMap = (Object) params[0].get("data");
Gson gson = new Gson();
Log.d("data map", "data map------" + gson.toJson(dataMap));
httpost.setEntity(new StringEntity(gson.toJson(dataMap)));
httpost.setHeader("Accept", "application/json");
httpost.setHeader("Content-type", "application/json");
DefaultHttpClient httpclient= Util.getClient();
HttpResponse response = httpclient.execute(httpost);
int statusCode = response.getStatusLine().getStatusCode();
Log.d("resonse code", "----------------" + statusCode);
if (statusCode == 200)
responseStr = EntityUtils.toString(response.getEntity());
if (statusCode == 404) {
responseStr = "{\n" +
"\"status\":\"fail\",\n" +
" \"data\":{\n" +
"\"ValidUser\":\"Service not available\",\n" +
"\"code\":\"404\"\n" +
"}\n" +
"}";
}
} catch (Exception e) {
e.printStackTrace();
}
return responseStr;
}
#Override
protected void onPreExecute() {
Asycdialog.setMessage(msg);
//show dialog
Asycdialog.show();
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
Asycdialog.dismiss();
restFulResult.onResfulResponse(s,task);
}
}
For more details and complete code please visit http://javaant.com/consume-a-restful-webservice-in-android/#.VwzbipN96Hs
Here is my Library That I have created for simple Webservice Calling,
You can use this by adding a one line gradle dependency -
compile 'com.scantity.ScHttpLibrary:ScHttpLibrary:1.0.0'
Here is the demonstration of using.
https://github.com/vishalchhodwani1992/httpLibrary

Categories