cURL in Java

Dharan Prajwal
4 min readJul 24, 2020

Have to call a service?

Have to transfer data using ftp / sftp protocols?

Have to send a mail?

Hmm, there are lot many things you can do with CURL

Let’s see a more common use case

Mr.Ravi wants to call a REST service ( of any Http method — POST / GET / DELETE … ).

He is coding in Java and for some purpose he doesn’t want to use HttpURLConnection or any other library to do that. He prefers a simple CURL.

So, there are ways by which Mr.Ravi can use CURL in Java — he can use a Maven dependency as mentioned in https://github.com/libetl/curl or just use ProcessBuilder which would imitate the way if CURL was done through a console / terminal.

Here, I will show you the simpler way of just replicating your console/ terminal tests ( just not limited to CURL ) through Java -

Java.lang.ProcessBuilder is our saviour.

Example Curl through ProcessBuilder -

ProcessBuilder pb = new ProcessBuilder("curl","--silent","--location","--request","POST",<URL>,"--header","Content-Type:application/x-www-form-urlencoded","--data-urlencode","inputParams=<Your Body>");

Here,

-- silent silents the progress stats which will be printed by CURL which appears as shown below
Source: https://www.cyberciti.biz/faq/curl-hide-progress-bar-output-linux-unix-macos/
--location tells CURL to follow the redirects which is present in location header of a response--request is the actual request which is followed by a http method [ POST / GET / DELETE / PUT / CREATE .. to name a few ] and then the target URL--header is the header of the request, all the required headers can follow this param--data-urlencode is followed by the request body which may be of any format as required by the end point

The next part of the code :

// errorstream of the process will be redirected to standard output
pb.redirectErrorStream(true);
// start the process
Process proc = pb.start();
/* get the inputstream from the process which would get printed on
* the console / terminal
*/
InputStream ins = proc.getInputStream();
// creating a buffered reader
BufferedReader read = new BufferedReader(new InputStreamReader(ins));
StringBuilder sb = new StringBuilder();read
.lines()
.forEach(line -> {
logger.debug("line>"+line);
sb.append(line);
});
// close the buffered reader
read.close();
/*
* wait until process completes, this should be always after the
* input_stream of processbuilder is read to avoid deadlock
* situations
*/
proc.waitFor();
/* exit code can be obtained only after process completes, 0
* indicates a successful completion
*/
int exitCode = proc.exitValue();
logger.debug("exit code::"+exitCode);
// finally destroy the process
proc.destroy();

A Tip:

Please be mindful on the position of proc.waitFor()

proc.waitFor() would pause the thread until the process is completed.

If in case we would wait for entire process to get completed and then collect the input_stream then there is a possibility where the response which you would get from the process would fill in the buffer completely and would wait for the input_stream to collect and at the same time input_stream would be collected only after the process ends.

This is a perfect example of Deadlock and CURL just hangs clueless and would freeze :)

So, let me re-write the above code for you just to give a hint on how NOT to write

// errorstream of the process will be redirected to standard output
pb.redirectErrorStream(true);
// start the process
Process proc = pb.start();
/*
* wait until process completes, this should be always after the
* input_stream of processbuilder is read to avoid deadlock
* situations
*/
proc.waitFor();
/* exit code can be obtained only after process completes, 0
* indicates a successful completion
*/
int exitCode = proc.exitValue();
logger.debug("exit code::"+exitCode);
/* get the inputstream from the process which would get printed on
* the console / terminal
*/
InputStream ins = proc.getInputStream();
// creating a buffered reader
BufferedReader read = new BufferedReader(new InputStreamReader(ins));

Final Code

try {ProcessBuilder pb = new ProcessBuilder("curl","--silent","--location","--request","POST",<URL>,"--header","Content-Type:application/x-www-form-urlencoded","--data-urlencode","inputParams=<Your Body>");// errorstream of the process will be redirected to standard output
pb.redirectErrorStream(true);
// start the process
Process proc = pb.start();
/* get the inputstream from the process which would get printed on
* the console / terminal
*/
InputStream ins = proc.getInputStream();
// creating a buffered reader
BufferedReader read = new BufferedReader(new InputStreamReader(ins));
StringBuilder sb = new StringBuilder();read
.lines()
.forEach(line -> {
logger.debug("line>"+line);
sb.append(line);
});
// close the buffered reader
read.close();
/*
* wait until process completes, this should be always after the
* input_stream of processbuilder is read to avoid deadlock
* situations
*/
proc.waitFor();
/* exit code can be obtained only after process completes, 0
* indicates a successful completion
*/
int exitCode = proc.exitValue();
logger.debug("exit code::"+exitCode);
// finally destroy the process
proc.destroy();
} catch (UnsupportedOperationException | IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}

Happy Coding! Please feel free to correct or leave your suggestions in comments below

--

--

Dharan Prajwal

Senior Software Engineer at Luxoft | Ex- Envestnet Yodlee | Freelancer | Knowledge Seeker