I have a problem with creating post requests and send json with Robospice google http java client. My problem is, that the server receives an empty request data. (Nothing in postData)
#Override
public AjaxResult loadDataFromNetwork() throws Exception {
JsonHttpContent jsonHttpContent = new JsonHttpContent(new JacksonFactory(), jsonObject);
//ByteArrayContent.fromString("application/json", jsonObject.toString())
HttpRequest request = getHttpRequestFactory().buildPostRequest(
new GenericUrl(baseUrl),
jsonHttpContent);
request.getHeaders().setContentType("application/json");
request.setParser(new JacksonFactory().createJsonObjectParser());
request.setContent(jsonHttpContent);
HttpResponse httpResponse = request.execute();
AjaxResult result = httpResponse.parseAs(getResultType());
return result;
}
Thanks in advance!
You can do something like this :
public class SignIn_Request extends GoogleHttpClientSpiceRequest<Login> {
private String apiUrl;
private JSONObject mJsonObject;
public SignIn_Request(JSONObject mJsonObject) {
super(Login.class);
this.apiUrl = AppConstants.GLOBAL_API_BASE_ADDRESS + AppConstants.API_SIGN_IN;
this.mJsonObject = mJsonObject;
}
#Override
public Login loadDataFromNetwork() throws IOException {
Ln.d("Call web service " + apiUrl);
HttpRequest request = getHttpRequestFactory()//
.buildPostRequest(new GenericUrl(apiUrl), ByteArrayContent.fromString("application/json", mJsonObject.toString()));
request.setParser(new JacksonFactory().createJsonObjectParser());
return request.execute().parseAs(getResultType());
}
}
Convert your JSON into byte array and include it in your post request.
I've been hunting around for a similar solution myself and I found a decent explanation of how Google want you to format the content.
I made POJO class and just added some getters and setters and used that for the data and it seemed to work for me.
google-http-java-client json update existing object
Related
I am trying to send a POST request on web server with Android Annotations REST Api, and I am trying to send an image as a Base64 String and video as a file.
The operation also needs a Bearer Auth but I have managed that without an error.
My RestClient interface is like this:
#Rest(rootUrl = NetworkConstants.BASE_URL, converters = {GsonHttpMessageConverter.class, StringHttpMessageConverter.class,
FormHttpMessageConverter.class},interceptors = {
HeadersRequestInterceptor.class })
public interface RestClient extends RestClientHeaders {
#Post(NetworkConstants.UPLOAD_URL)
VideoUploadResponse uploadVideo(MultiValueMap<String,Object> model);
}
And my Request is like this:
MultiValueMap dataMultiPart = new LinkedMultiValueMap<>();
File file = new File(path);
dataMultiPart.add("thumbnail", bitmapString);
dataMultiPart.add("media", new FileSystemResource(file));
try {
VideoUploadResponse resonse = restClient.uploadVideo(dataMultiPart);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
In my interceptor class I have tried both this
public class HeadersRequestInterceptor implements ClientHttpRequestInterceptor {
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().add("content-type", MediaType.MULTIPART_FORM_DATA_VALUE);
request.getHeaders().add("authorization", "Bearer sometokenvalue");
return execution.execute(request, body);
}
}
and this
public class HeadersRequestInterceptor implements ClientHttpRequestInterceptor {
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
request.getHeaders().setContentType(MediaType.MULTIPART_FORM_DATA);
request.getHeaders().add("authorization", "Bearer sometokenvalue");
return execution.execute(request, body);
}
}
And I am getting the exception Invalid token character ' ' in token "json charset=UTF-8" everytime.
At first I thought there might be a problem with the auth token, but there is not.And when I try this request with postman there is no such error.
Postman Request Example
What am I doing wrong?
This can be achieved in several ways:
#Rest(rootUrl = rootUrl = NetworkConstants.BASE_UR, converters = FormHttpMessageConverter.class, interceptors = HeadersRequestInterceptor.class)
public interface RestClient extends RestClientHeaders {
#Post(NetworkConstants.UPLOAD_URL)
#RequiresHeader(HttpHeaders.CONTENT_TYPE)
VideoUploadResponse uploadVideo(#Path int id, #Body MultiValueMap<String, Object> data);
}
MultiValueMap dataMultiPart = new LinkedMultiValueMap<>();
File file = new File(path);
dataMultiPart.add("thumbnail", bitmapString);
dataMultiPart.add("media", new FileSystemResource(file));
try {
restClient.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.MULTIPART_FORM_DATA_VALUE);
VideoUploadResponse resonse = restClient.uploadVideo(dataMultiPart);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
It is even easier in AA 4.0:
#Rest(rootUrl = rootUrl = NetworkConstants.BASE_UR, converters = FormHttpMessageConverter.class, interceptors = HeadersRequestInterceptor.class)
public interface RestClient extends RestClientHeaders {
#Post(NetworkConstants.UPLOAD_URL)
VideoUploadResponse uploadVideo(#Part String thumbnail, #Part FileSystemResource media);
}
restClient.uploadVideo(bitmapString, new FileSystemResource(file));
So it turns out problem was not because of me, but the server side.
Server is sending "application/json charset=UTF-8" as Content-Type, but Spring framework is strict in parsing headers, and it sees the space character between "json" and "charset" as an error.Normally it should be "application","json;charset=utf-8”;
That's why problem was happening while using Android Annotations or Retrofit.
It was working well with Postman because it is less strict in parsing headers.
I am using now Google Volley for network communication and the problem is gone.
I am asking this question based on the answers in this link
POST request via RestTemplate in JSON
I actually wanted to send JSON from client and receive the same at REST server. Since the client part is done in the link I mentioned above. For the same how would I handle that request at server end.
CLIENT:
// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
.exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
}
SERVER:
#RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(#RequestBody HttpEntity<String> entity) {
JSONObject jsonObject = new JSONObject(entity.getBody());
String username = jsonObject.getString("username");
return new ResponseEntity<>(username, HttpStatus.OK);
}
This gives me 400 bad request error at client side. Hoping for some clues about how to handle this at server side.
HTTPEntity should not be used in your server method. Instead use the argument which is being passed to HTTPEntity from your client. In your case it has to String since you are passing string from client. Below code should work for you.
#RequestMapping(method=RequestMethod.POST, value = "/login")
public ResponseEntity<String> login(#RequestBody String jsonStr) {
System.out.println("jsonStr " + jsonStr);
JSONObject jsonObject = new JSONObject(jsonStr);
String username = jsonObject.getString("username");
return new ResponseEntity<String>(username, HttpStatus.OK);
}
My advice is to create bean class and use it in server and client instead of converting it to String. It will improve readability of the code.
When using the Spring RestTemplate, I usually prefer to exchange objects directly. For example:
Step 1: Declare and define a data holder class
class User {
private String username;
private String password;
... accessor methods, constructors, etc. ...
}
Step 2: Send objects of this class to the server using RestTemplate
... You have a RestTemplate instance to send data to the server ...
// You have an object to send to the server, such as:
User user = new User("user", "secret");
// Set HTTP headers for an error-free exchange with the server.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Generate an HTTP request payload.
HttpEntity<User> request = new HttpEntity<User>(user, headers);
// Send the payload to the server.
restTemplate.exchange("[url]", [HttpMethod], request, User.class);
Step 3: Configure a ContentNegotiatingViewResolver on the server
Declare a bean of the type ContentNegotiatingViewResolver in the Spring XML or Java configuration. This will help the server automatically bind HTTP requests with bean objects.
Step 4: Receive the request on the server
#RestController
#RequestMapping("/user")
class UserAPI {
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public User create(User user) {
// Process the user.
// Possibly return the same user, although anything can be returned.
return user;
}
}
The ContentNegotiatingViewResolver ensures that the incoming request gets translated into a User instance without any other intervention.
Step 5: Receive the response on the client
// Receive the response.
HttpEntity<User> response = restTemplate.exchange("[url]", [HttpMethod], request, User.class);
// Unwrap the object from the response.
user = response.getBody();
You will notice that the client and the server both use the same bean class (User). This keeps both in sync as any breaking change in the bean structure would immediately cause a compilation failure for one or both, necessitating a fix before the code is deployed.
I am working with robospice. Now I want to upload file.
I used SpringAndroidSpiceService and write my own request like this :
public class UploadFileRequest extends SpringAndroidSpiceRequest<String>{
private static final String TAG = "UploadFileRequest";
private UploadRequestModel requestModel;
private String link;
public UploadFileRequest(UploadRequestModel model, String link) {
super(String.class);
requestModel = model;
this.link = link;
}
#Override
public String loadDataFromNetwork() throws Exception {
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
parts.add("file1", new FileSystemResource(requestModel.getFile1()));
parts.add("file2", new FileSystemResource(requestModel.getFile1()));
HttpHeaders headers = new HttpHeaders();
HttpEntity<MultiValueMap<String, Object>> request =
new HttpEntity<MultiValueMap<String, Object>>(parts, headers);
return getRestTemplate().postForObject(link, request, String.class);
}
}
I can send the files now. But I faced a problem.
After the files have sent. My files on disk are almost deleted. It's size is zero.
Do you know why ? and how can I resolve it ?
Thank you very much for any help.
I am on of the authors of RS. The problem you face is not related to RS directly but to Spring Android. I suggest you write to their forum to get an answer. Sorry, but we can't tell you more.
Stéphane
this.message.setApi_key(ConfigurationBean.getTab_id());
this.message.setApi_password(ConfigurationBean.getTab_assword());
this.message.setNursery_id(ConfigurationBean.getNursery_id());
url=ConfigurationBean.getNursery_url()+"/api/v1/installation.php";
try {
list=service.getConfiguration(admin, pass);
} catch (Exception e) {
Log.e("request", ""+e.getMessage());
}
// Add the Jackson and String message converters
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
// Make the HTTP POST request, marshaling the request to JSON, and the response to a String
String response = restTemplate.postForObject(url, message, String.class);
return response;
this is my code,
before i was getting the same problem ,not its working fine u can try this message enter code hereconverter which will help
I have Java web application server [ acts like server ].
In Android application, using httppost i have calling the restwebserive server.
My calling is hit the webservice with the response code 200.
Now i want to pass the java class object as like parameter.
sample java class:
public Class Sample{
public String Username;
public String getUsername()
{
return Username;
}
public void setUsername(String user){
this.Username = user;
}}
Used code :[ Is not passing my class object to server ]
Sample sam = new Sample();
sam.setUsername("Test");
JSONObject json = new JSONObject();
json.put("Sample", sam);
StringEntity se = new StringEntity(json.toString());
Httppostrequest.setEntity(se);
when i debugging the server the sample object parameter input is empty.[Not passed properly]
How to pass the class object via http post in android?
Please help me on this.
Thanks in advance,
Kums
if you use apache library you can do it one line
JSONSerializer.toJSON(sam);
otherwise i think you have to send it as
Sample sam = new Sample();
sam.setUsername("Test");
JSONObject json = new JSONObject();
json.put("sample", sam.getUserName());
StringEntity se = new StringEntity(json.toString());
Httppostrequest.setEntity(se);
Here is a code snippet
public void callWebService(String q){
HttpClient httpclient = new DefaultHttpClient();
HttpGet request = new HttpGet(URL + q);
request.addHeader("deviceId", deviceId);
ResponseHandler<string> handler = new BasicResponseHandler();
try {
result = httpclient.execute(request, handler);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
httpclient.getConnectionManager().shutdown();
Log.i(tag, result);
} // end callWebService()
}
Use this method to call your webservice
I have built a library for doing async requests, you can send parameter requests as www.somedomain.com/action?param1="somevalue" etc.. and also there is the option to use string body.
https://github.com/darko1002001/android-rest-client
Check it out, it might be helpful.
I'm attempting to use an HttpDelete object to invoke a web service's delete method. The web service's code parses JSON from the message's body. However, I'm failing to understand how to add a body to an HttpDelete object. Is there a way to do this?
With HttpPut and HttpPost, I call the setEntity method and pass in my JSON. There doesn't appear to be any such method for HttpDelete.
If there is no way to set a body for an HttpDelete object, could you please link me to a resource that uses a super class of HttpDelete such that I can set the method (delete) and set a body. I know that isn't ideal, but at this point I can't alter the web service.
Have you tried overriding HttpEntityEnclosingRequestBase as follows:
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import java.net.URI;
import org.apache.http.annotation.NotThreadSafe;
#NotThreadSafe
class HttpDeleteWithBody extends HttpEntityEnclosingRequestBase {
public static final String METHOD_NAME = "DELETE";
public String getMethod() { return METHOD_NAME; }
public HttpDeleteWithBody(final String uri) {
super();
setURI(URI.create(uri));
}
public HttpDeleteWithBody(final URI uri) {
super();
setURI(uri);
}
public HttpDeleteWithBody() { super(); }
}
That will create a HttpDelete-lookalike that has a setEntity method. I think the abstract class does almost everything for you, so that may be all that's needed.
FWIW, the code is based on this source to HttpPost that Google turned up.
Following Walter Mudnt advice, you can use this code. It works, just made it while testing my REST webservice.
try {
HttpEntity entity = new StringEntity(jsonArray.toString());
HttpClient httpClient = new DefaultHttpClient();
HttpDeleteWithBody httpDeleteWithBody = new HttpDeleteWithBody("http://10.17.1.72:8080/contacts");
httpDeleteWithBody.setEntity(entity);
HttpResponse response = httpClient.execute(httpDeleteWithBody);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
To access the response you can simply do: response.getStatusLine();
There are different interpretation in the question whether the body is allowed or not in the HTTP DELETE request. See this for example. In the HTTP 1.1 specification it is not explicitly prohibied. In my opinion you should not use body in the HTTP DELETE.
Nevertherless I think that you should use URL like mysite/myobject/objectId (shop.com/order/1234) where the objectId (a part of the url) is the additional information. As an alternative you can use URL parameters: mysite/myobject?objectName=table&color=red to send additipnal information to the server in the HTTP DELETE request. The part starting with '?' is the urlencoded parameters devided dy '&'.
If you want to send more complex information you can convert the data to JSON with respect of DataContractJsonSerializer or JavaScriptSerializer and then send the converted data (a string which I name myJsonData later) also as the parameter: mysite/myobject?objectInfo=myJsonData.
If you need to send too much additionnal data as a part of HTTP DELETE request so that you have problem with the URL length then you should probably better change the design of your application.
UPDATED: Iy you do want send some body per HTTP DELETE you can do this for example like following
// somewhere above add: using System.Net; and using System.IO;
WebClient myWebClient = new WebClient ();
// 1) version: do simple request
string t= myWebClient.UploadString ("http://www.examples.com/", "DELETE", "bla bla");
// will be send following:
//
// DELETE http://www.examples.com/ HTTP/1.1
// Host: www.examples.com
// Content-Length: 7
// Expect: 100-continue
// Connection: Keep-Alive
//
//bla bla
// 2) version do complex request
Stream stream = myWebClient.OpenWrite ("http://www.examples.com/", "DELETE");
string postData = "bla bla";
byte[] myDataAsBytes = Encoding.UTF8.GetBytes (postData);
stream.Write (myDataAsBytes, 0, myDataAsBytes.Length);
stream.Close (); // it send the data
// will be send following:
//
// DELETE http://www.examples.com/ HTTP/1.1
// Host: www.examples.com
// Content-Length: 7
// Expect: 100-continue
//
// bla bla
// 3) version
// create web request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create ("http://www.examples.com/");
webRequest.Method = "DELETE";
webRequest.ServicePoint.Expect100Continue = false;
// post data
Stream requestStream = webRequest.GetRequestStream ();
StreamWriter requestWriter = new StreamWriter (requestStream);
requestWriter.Write (postData);
requestWriter.Close ();
//wait for server response
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse ();
// send following:
// DELETE http://www.examples.com/ HTTP/1.1
// Host: www.examples.com
// Content-Length: 7
// Connection: Keep-Alive
//
// bla bla
the full code could be a little more complex, but this one already will work. Nevertheless I continue to say that Web Service needed data in the body of HTTP DELETE request is bad designed.
use this,
class MyDelete extends HttpPost{
public MyDelete(String url){
super(url);
}
#Override
public String getMethod() {
return "DELETE";
}
}
in retrofit
import okhttp3.Request;
private final class ApiInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
Request oldRequest = chain.request();
Request.Builder builder = oldRequest.newBuilder();
if(condition) {
return chain.proceed(builder.build().newBuilder().delete(builder.build().body()).build());
}
return chain.proceed(builder.build());
}
}
you have to trigger condition, via something and potentially have to do some filtering for the url/header/body to remove the trigger,
unless the delete url/body/header is unique enough to not collide with post or get requests.