Handling Multipart File Uploads in JAX-RS 2.1 (on WebSphere Liberty)
In transitioning from JAX-RS 1.x to JAX-RS 2.x, one significant change developers may encounter is how multipart file uploads are handled.
Handling Multipart File Uploads in JAX-RS 2.1 (on WebSphere Liberty)
In transitioning from JAX-RS 1.x to JAX-RS 2.x, one significant change developers may encounter is how multipart file uploads are handled.
With JAX-RS 1, file handling was often done using:
@FormDataParam("file") File file;
However, this approach doesn’t work the same way in JAX-RS 2 environments like WebSphere Liberty, which do not provide native support for @FormDataParam.
Instead, we need to rely on the raw **HttpServletRequest** to access multipart parts manually, which requires more boilerplate but offers flexibility.
This blog is inspired and largely made possible by Jason Lee’s great guide, which helped me understand how to implement file upload support cleanly in a Liberty JAX-RS 2.1 environment.
Let’s walk through a working example step-by-step:
Step 1: pom.xml – Setting up Dependencies
We create a WAR-based Maven project and add JAX-RS 2.1 and Servlet 4.0 dependencies. Since we’re deploying to WebSphere Liberty, these APIs are marked as provided.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>jaxrs-was-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- JAX-RS API -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>jaxrs-was-demo</finalName>
</build>
</project>
Step 2: server.xml – Liberty Server Configuration
Enable the JAX-RS 2.1 and Servlet 4.0 features and point the server to your deployed WAR.
<server description="JAX-RS 2.1 Application Server">
<featureManager>
<feature>jaxrs-2.1</feature>
<feature>servlet-4.0</feature>
</featureManager>
<httpEndpoint id="defaultHttpEndpoint"
host="*"
httpPort="9080"
httpsPort="9443" />
<application location="/config/jaxrs-was-demo.war" name="jaxrs-was-demo">
<context-root>/</context-root>
</application>
</server>
Step 3: web.xml – Register the JAX-RS Servlet
Use the Liberty-specific IBMRestServlet and configure it to load your JAX-RS Application class.
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<display-name>JAX-RS Liberty Demo</display-name>
<servlet>
<servlet-name>was</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.example.rest.ApplicationConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<multipart-config />
</servlet>
</web-app>
You’ll also want to include a proper <multipart-config> block here to enable multipart parsing via the servlet container.
Step 4: ApplicationConfig.java – Register JAX-RS Resources
Set the base path /api and register your REST resource class.
@ApplicationPath("/api")
public class ApplicationConfig extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(HelloResource.class);
return classes;
}
}
Step 5: HelloResource.java – Implement the Upload Endpoint
This resource handles two things: a test GET endpoint and a POST endpoint to accept multipart file uploads using raw servlet APIs.
@Path("/hello")
public class HelloResource {
@GET
public String sayHello() {
return "Hello from JAX-RS 2.1 on WebSphere!";
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
public String createDocumentPost(@Context HttpServletRequest request) {
MultipartRequestMap map = new MultipartRequestMap(request);
File uploadedFile = map.getFileParameter("file");
return "File size: " + uploadedFile.length() + ", file path: " + uploadedFile.getAbsolutePath();
}
}
Step 6: MultipartRequestMap.java – Handle Multipart Parsing
Since Liberty doesn’t provide @FormDataParam-style injection, we manually parse the HttpServletRequest to extract file parts and form fields.
Key highlights:
- Parses
Partobjects from the request. - Distinguishes between file uploads and text fields.
- Saves uploaded files temporarily and cleans them up.
public class MultipartRequestMap extends HashMap<String, List<Object>> {
private static final String DEFAULT_ENCODING = "UTF-8";
private final String encoding;
private final String tempLocation;
public MultipartRequestMap(HttpServletRequest request) {
this(request, System.getProperty("java.io.tmpdir"));
}
public MultipartRequestMap(HttpServletRequest request, String tempLocation) {
super();
this.tempLocation = tempLocation;
String tempEncoding = request.getCharacterEncoding();
if (tempEncoding == null) {
try {
request.setCharacterEncoding(DEFAULT_ENCODING);
tempEncoding = DEFAULT_ENCODING;
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(MultipartRequestMap.class.getName()).log(Level.SEVERE, null, ex);
}
}
this.encoding = tempEncoding;
try {
for (Part part : request.getParts()) {
String fileName = part.getSubmittedFileName();
if (fileName == null) {
putMulti(part.getName(), getValue(part));
} else {
processFilePart(part, fileName);
}
}
} catch (IOException | ServletException ex) {
Logger.getLogger(MultipartRequestMap.class.getName()).log(Level.SEVERE, null, ex);
}
}
public String getStringParameter(String name) {
List<Object> list = get(name);
return (list != null) ? (String) list.get(0) : null;
}
public File getFileParameter(String name) {
List<Object> list = get(name);
return (list != null) ? (File) list.get(0) : null;
}
private void processFilePart(Part part, String fileName) throws IOException {
File tempFile = new File(tempLocation, fileName);
tempFile.createNewFile();
tempFile.deleteOnExit();
try (
BufferedInputStream input = new BufferedInputStream(part.getInputStream(), 8192);
BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(tempFile), 8192)
) {
byte[] buffer = new byte[8192];
int length;
while ((length = input.read(buffer)) > 0) {
output.write(buffer, 0, length);
}
} catch (Exception e) {
Logger.getLogger(MultipartRequestMap.class.getName()).log(Level.SEVERE, null, e);
}
part.delete();
putMulti(part.getName(), tempFile);
}
private String getValue(Part part) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(part.getInputStream(), encoding));
StringBuilder value = new StringBuilder();
char[] buffer = new char[8192];
int length;
while ((length = reader.read(buffer)) > 0) {
value.append(buffer, 0, length);
}
return value.toString();
}
private <T> void putMulti(final String key, final T value) {
List<Object> values = get(key);
if (values == null) {
values = new ArrayList<>();
put(key, values);
}
values.add(value);
}
}
This is a clean, reusable utility for multipart handling without relying on external libraries.
Step 7: Dockerfile – Build and Deploy with Liberty
Here’s a simple Dockerfile to containerize your app with Open Liberty:
FROM open-liberty:24.0.0.9-full-java8-openj9
WORKDIR /config
RUN configure.sh
COPY server.xml /config/server.xml
COPY target/jaxrs-was-demo.war /config/jaxrs-was-demo.war
Build and run:
docker build -t jaxrs-upload-demo .
docker run -p 9080:9080 jaxrs-upload-demo
Summary
The jump from JAX-RS 1.x to 2.x simplifies many things, but file uploads in some runtimes (like Liberty) still require a bit of custom plumbing. This example illustrates:
- How to configure Liberty for JAX-RS 2.1 and multipart handling
- Manual parsing of multipart data using servlet APIs
- Avoiding external libraries and working with native Java EE features
Thank you!
메타데이터
- post_id
- b83dbc88be2c
- slug
- handling-multipart-file-uploads-in-jax-rs-2-1-on-websphere-liberty-b83dbc88be2c
- url
- https://medium.com/@keylearn/handling-multipart-file-uploads-in-jax-rs-2-1-on-websphere-liberty-b83dbc88be2c
- canonical_url
- https://medium.com/@keylearn/handling-multipart-file-uploads-in-jax-rs-2-1-on-websphere-liberty-b83dbc88be2c
- author_url
- https://medium.com/@keylearn
- status
- ok
- fetched_at
- 2026-07-20 00:12:32