The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:
Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Overview
In this tutorial, we will illustrate how to do a multipart upload operation using HttpClient 5.
If you want to dig deeper and learn other cool things you can do with the HttpClient, head over to the main HttpClient tutorial.
2. Using the AddPart Method
Letβs start by looking at the MultipartEntityBuilder object to add parts to an Http entity which will then be uploaded via a POST operation.
This is a generic method to add parts to an HttpEntity representing the form.
Example 2.1. β Uploading a Form with Two Text Parts and a File
final File file = new File(url.getPath());
final FileBody fileBody = new FileBody(file, ContentType.DEFAULT_BINARY);
final StringBody stringBody1 = new StringBody("This is message 1", ContentType.MULTIPART_FORM_DATA);
final StringBody stringBody2 = new StringBody("This is message 2", ContentType.MULTIPART_FORM_DATA);
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.LEGACY);
builder.addPart("file", fileBody);
builder.addPart("text1", stringBody1);
builder.addPart("text2", stringBody2);
final HttpEntity entity = builder.build();
post.setEntity(entity);
try(CloseableHttpClient client = HttpClientBuilder.create()
.build()) {
client.execute(post, response -> {
//do something with response
});
}
Note that weβre instantiating the File object by also specifying the ContentType value to be used by the server.
Also, note that the addPart method has two arguments, acting like key/value pairs for the form. These are only relevant if the server side actually expects and uses parameter names β otherwise, theyβre ignored.
3. Using the addBinaryBody and addTextBody Methods
A more direct way to create a multipart entity is to use the addBinaryBody and AddTextBody methods. These methods work for uploading text, files, character arrays, and InputStream objects. Letβs illustrate how with simple examples.
Example 3.1. β Uploading Text and a Text File Part
final File file = new File(url.getPath());
final String message = "This is a multipart post";
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.LEGACY);
builder.addBinaryBody("file", file, ContentType.DEFAULT_BINARY, TEXTFILENAME);
builder.addTextBody("text", message, ContentType.DEFAULT_BINARY);
final HttpEntity entity = builder.build();
post.setEntity(entity);
try(CloseableHttpClient client = HttpClientBuilder.create()
.build()) {
client.execute(post, response -> {
//do something with response
});
}
Note that the FileBody and StringBody objects are not needed here.
Also important, most servers do not check the ContentType of the text body, so the addTextBody method may omit the ContentType value.
The addBinaryBody API accepts a ContentType β but it is also possible to create the entity just from a binary body and the name of the form parameter holding the file. As stated in the previous section, some servers will not recognize the file if the ContentType value is not specified.
Next, weβll add a zip file as an InputStream, while the image file will be added as a File object:
Example 3.2. β Uploading aZip File, an Image File, and a Text Part
final URL url = Thread.currentThread()
.getContextClassLoader()
.getResource("uploads/" + ZIPFILENAME);
final URL url2 = Thread.currentThread()
.getContextClassLoader()
.getResource("uploads/" + IMAGEFILENAME);
final InputStream inputStream = new FileInputStream(url.getPath());
final File file = new File(url2.getPath());
final String message = "This is a multipart post";
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.LEGACY);
builder.addBinaryBody("file", file, ContentType.DEFAULT_BINARY, IMAGEFILENAME);
builder.addBinaryBody("upstream", inputStream, ContentType.create("application/zip"), ZIPFILENAME);
builder.addTextBody("text", message, ContentType.TEXT_PLAIN);
final HttpEntity entity = builder.build();
post.setEntity(entity);
try(CloseableHttpClient client = HttpClientBuilder.create()
.build()) {
client.execute(post, response -> {
//do something with response
});
}
Note that the ContentType value can be created on the fly, as in the example above for the zip file.
Finally, not all servers acknowledge InputStream parts. The server we instantiated in the first line of the code recognizes InputStreams.
Letβs now look at another example where addBinaryBody is working directly with a byte array:
Example 3.3. β Uploading a Byte Array and Text
final String message = "This is a multipart post";
final byte[] bytes = "binary code".getBytes();
final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.LEGACY);
builder.addBinaryBody("file", bytes, ContentType.DEFAULT_BINARY, TEXTFILENAME);
builder.addTextBody("text", message, ContentType.TEXT_PLAIN);
final HttpEntity entity = builder.build();
post.setEntity(entity);
try(CloseableHttpClient client = HttpClientBuilder.create()
.build()) {
client.execute(post, response -> {
//do something with response
});
}
Notice the ContentType β which is now specifying binary data.
4. Conclusion
This article has presented the MultipartEntityBuilder as a flexible object which offers multiple API choices to create a multipart form.
The examples have also shown how to use the HttpClient to upload a HttpEntity that is similar to a form entity.
