2

I'm trying to write a rest service to upload a file along with some other file information, using Jersey + Jackson.

Using multipart, the file is uploaded correctly, and simple fields are OK as well, but the POJO that's supposed to contain additional data, is always null.

Simplified example

POJO:

public class Test {

 public String name;

 public Test() {}

 public String getName() {
    return name;
 }
 public void setName(String name) {
    this.name = name;
 }
}

Application:

@ApplicationPath("myapp")

public class JerseyApp extends ResourceConfig {

 public JerseyApp() {

  register(MultiPartFeature.class);

  register(JacksonFeature.class);

  packages("com.test.rest");

  // Enable Tracing support.
  property(ServerProperties.TRACING, "ALL");
 }
}

Service:

@Path("file")
public class FileRestService {

 @POST
 @Path("/upload1")
 @Consumes(MediaType.MULTIPART_FORM_DATA)
 public Response createFile1(@FormDataParam("doc") Test doc) {
    //doc is always null
    return Response.ok(doc.getName()).build();
 }

 @POST
 @Path("/upload2")
 @Consumes(MediaType.APPLICATION_JSON)
 public Response createFile2(Test doc) {
    //doc is created ok
    return Response.ok(doc.getName()).build();
 }

web.xml is empty

pom.xml

<dependencies>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet-core</artifactId>
        <version>2.22</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>          
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.22</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.22</version>
    </dependency>       
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.6.2</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.22</version>
    </dependency>       
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-api</artifactId>
        <version>2.3</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.3</version>
    </dependency>
    <dependency>
        <groupId>org.fusesource.jansi</groupId>
        <artifactId>jansi</artifactId>
        <version>1.11</version>
    </dependency>
</dependencies>

Data is JSON and I'm testing with DHC/Postman, if it makes any difference.

Any idea why when using multipart, the pojo/bean is null?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
Mihai Ocneanu
  • 693
  • 6
  • 17

1 Answers1

6

See related problem here. The problem is that the Content-Type is not set for the doc part. In that post (answer) I didn't know how to set it in Postman, and I still haven't found a solution.

If you use a tool like cURL (which I'll just say is the best tool ever for REST development :-), you can make set the Content-Type of each part. If you don't know already cURL is a command like tool that you can use to make HTTP (and other protocol) requests. For example, you can do something like

curl -v -X POST http://localhost:8080/api/file \
        -F 'doc={"hello":"world"};type=application/json'

This makes a POST request as multipart and sets the doc part to be of type application/json.

You will also find some useful examples of setting here


UPDATE

Another options, if you simply can't set the individual parts' Content-Type, is to set the type programmatically before deserialing. For example

 @POST
 @Path("/upload1")
 @Consumes(MediaType.MULTIPART_FORM_DATA)
 public Response createFile1(@FormDataParam("doc") FormDataBodyPart part) {
    part.setMediaType(MediaType.APPLICATION_JSON_TYPE);
    Test doc = part.getValueAs(Test.class);
    return Response.ok(doc.getName()).build();
 }
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • One thing you can try, that I am too lazy to test is to use a file with a `.json` extension. I imagine that Postman will discover the type by the extension. This is just a theory, as it works for `.png` files. It set the `Content-Type` to `image/png` – Paul Samsotha Sep 30 '15 at 01:39