0

I am trying to send an uploaded file (FormData from Angular) and a string in the same HTTP POST request to backend (Java using Grizzly server and Ajax for REST services). The problem is that I receive HTTP 400 Bad Request because the file is not correctly mapped:

jersey message: Can not construct instance of java.io.InputStream: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type

In Frontend I have a class named Form created using ng g class Form, which contains:

export class Form {
    private file:FormData;
    private bookName: String;

    constructor(file:FormData, bookName: String) {
        this.file = file;
        this.bookName = bookName;
    }
}

The HTTP POST method from Frontend is:

  sendFormData() {
    const form  = new Form(this.testData, this.bookName);

    this.pdfService.sendFormData(form).subscribe((res) => {
      console.log(res);
    });
  }

Above this.testData has the type FormData and this.bookName is a string. They both contain the expected input values.

The pdfService.sendFormData is:

  public sendFormData(form: Form) {
    console.log("sending to " + this.baseUrl + "uploadFile")
    return this.http.post(this.baseUrl + "uploadFile", form, { responseType: 'text' });
  }

In Backend I have a class Form.java (the mapped class):

public class Form {
    String bookName;
    InputStream file;
    ... (getters & setters & constructor)
}

and the HTTP POST method is:

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.TEXT_HTML)
    @Path("uploadFile")
    public Response convertPdfToHtml(Form form) {
            ...
    }

To get the mapped string I use: form.getBookName() and to get the mapped file I use: form.getFile().

As I said, the problem is that the file from Frontend is not correctly mapped on the InputStream from Backend.

What type should I use to map a FormData from Frontend to a type in Backend? Or what other implementations could I use to send a file and a string in the same POST request?

Thanks.

1 Answer 1

2

in POST method you should provide object of type FormData, and there

export class Form {
  private file: File;
  private bookName: String;

  constructor(file:File, bookName: String) {
    this.file = file;
    this.bookName = bookName;
  }
}


public sendFormData(form: Form) {
  const formData = new FormData();
  formData.append('bookName', form.bookName);
  formData.append('file', form.file, form.file.name);

  console.log("sending to " + this.baseUrl + "uploadFile")
  return this.http.post(this.baseUrl + "uploadFile", formData, {responseType: 'text'});
}

and you'll get post with content-type multipart/form-data

Sign up to request clarification or add additional context in comments.

5 Comments

Why @Consumes(MediaType.MULTIPART_FORM_DATA) and not @Consumes(MediaType.APPLICATION_JSON) if I map the values on a Class? Thus, I tried with MULTIPART_FORM_DATA and it gives me 415 - unsupported media type. Also, I don't understand why I also need: form.append('bookName', bookName) and form.append('file', file, file.name). I am calling the constructor: const form = new Form(this.testData, this.bookName); thus the bookName and the file are already set. Also I can't do form.append('file', file, file.name).
couse JSON cannot caryy InputStream, it's text format, i'll update my answer to show, how to make POST request
You can use JSON, but you'll have to include your file content as text(usually also convert to Base64). In this approach backend always get whole payload, even if is not interesed
I prefer not sending the content as text but the whole file and thus I need to use MULTIPART_FORM_DATA, as you said.
It worked. I didn't use the Form class in Frontend anymore, just the FormData type with the append method to add an object. In Backend, I used the following signature: @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.TEXT_HTML) @Path("uploadFile") public Response convertPdfToHtml( @FormDataParam("bookName") String bookName, @FormDataParam("file") InputStream uploadedInputStream, @FormDataParam("file") FormDataContentDisposition fileDetail) {...}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.