During the development of my Android application I had to find a way to upload a file and send textual data in the same call. In order to do so, I replaced the usage of Google's http client with apache httpclient, so I could use the multipart format.
However now the app crashes on the following line:
HttpClient httpclient = HttpClientBuilder.create().build();
With the error:
java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE
I have found this answer related to my issue:
java.lang.NoSuchFieldError: org.apache.http.message.BasicLineFormatter.INSTANCE
The answer states that the apache httpclient is overlapping with an older version still kept in the android native libraries and suggests to repackage it using the maven shader plugin.
However, I don't understand what does it mean exactly and/or how to do so. I tried looking it up but the shader plugin page contains very little information of what exactly it does and I was mainly left confused.
What exactly does it mean to repackage the apache client and what side effects it may have? How exactly do I do it? And finally, is there a simpler solution to my problem?
This is the method I wrote to send http post requests:
NOTE: it worked when the first line was HttpClient httpclient = new DefaultHttpClient();
, but it displayed a warning that the DefaultHttpClient
was deprecated and I should use the HttpClientBuilder
instead. I'm trying to avoid using deprecated methods.
ANOTHER NOTE: The function below is part of my extention of AsyncTask. Could that be the problem?
public String postData(PostData req) {
HttpClient httpclient = HttpClientBuilder.create().build();
try {
HttpPost postRequest = new HttpPost(new URI(getString(R.string.connection_target)));
if(req.getURL() != null) {
postRequest = new HttpPost(new URI(req.getURL()));
}
//if no files are needed to be sent, use regular HTTP POST format instead of multipart
if(req.getFileMap().isEmpty()) {
List<NameValuePair> reqKeyValue = new ArrayList<NameValuePair>();
reqKeyValue.add(new BasicNameValuePair("request_id", requestID));
for(Entry<String, String> current : req.getTextValues().entrySet()) {
reqKeyValue.add(new BasicNameValuePair(current.getKey(), current.getValue()));
}
postRequest.setEntity(new UrlEncodedFormEntity(reqKeyValue));
} else {
//binary data is included in the request, so use multipart format
MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
//Add request ID to the message
entityBuilder.addTextBody("request_id", requestID);
for(Entry<String, String> current : req.getTextValues().entrySet()) {
entityBuilder.addTextBody(current.getKey(), current.getValue());
}
for(Entry<String, File> current : req.getFileMap().entrySet()) {
entityBuilder.addBinaryBody(current.getKey(), current.getValue(), ContentType.DEFAULT_BINARY, "image.jpeg");
//TODO send the file bytes in chunks
}
HttpEntity entity = entityBuilder.build();
postRequest.setEntity(entity);
}
ResponseHandler<String> responseHandler = new BasicResponseHandler();
//send the variable and value, in other words post, to the URL
String responseBody = httpclient.execute(postRequest, responseHandler);
Log.d("tom.debug", responseBody);
return responseBody;
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
PostData
is a class I wrote that holds 2 maps. One is <String, String>
and another is <String, File>
, they are to be sent as key value pairs in the post request.