2

I have a form that includes an object bound to the html with ng-bind. The same form includes a fileupload widget: <input type="file" id="uploadedFile" name="uploadedFile">.

I'm submitting this to a Java Restlet. I am able to get the File in the restlet but the json that should represent my object is null. Is there a way to solve this?

Here's my code. On the angular side:

function saveMap2(map, fileToUpload) {

    var formData = new FormData();
    formData.append("map", map);
    formData.append("file", fileToUpload);

    var deferred = $q.defer();
    $http.post(REST_SAVE_MAP_URI, formData, {
        transformRequest: angular.identity,
        headers: {'Content-Type': undefined}
    })
    .then(
      function (response) {
        deferred.resolve(response.data);
    },
    function(errResponse) {
        console.error('Error while saveMap');
        deferred.reject(errResponse);
    });
    return deferred.promise;
}

On the Restlet side:

@Post
public Representation doPost(Representation entity) {
    try {
        System.out.println("Media type? " + entity.getMediaType());
        DiskFileItemFactory factory = new DiskFileItemFactory();
        factory.setSizeThreshold(1000240);
        RestletFileUpload upload = new RestletFileUpload(factory);
        FileItemIterator fileIterator = upload.getItemIterator(entity);

        while (fileIterator.hasNext()) {
               FileItemStream fi = fileIterator.next();
               String fieldName = fi.getFieldName();
               String contentType = fi.getContentType();
               System.out.println("FIELD = " + fieldName + ": " + fi);
               if (!fi.isFormField()) {
                  String fileName = fi.getName();
                  System.out.println("name? " + fileName);

                  InputStream is = new BufferedInputStream(fi.openStream());
                  BufferedOutputStream output = null;

                  try {
                      output = new BufferedOutputStream(new FileOutputStream("/path/" + fileName, false));
                      int data = -1;
                      while ((data = is.read()) != -1) {
                          output.write(data);
                      }
                  } finally {
                      is.close();
                      output.close();
                  }
               } 
        }
  }

The result is that the image I'm uploading is saved correctly, but I don't know how to get the map json.

Here's some output:

Media type? multipart/form-data; boundary=----WebKitFormBoundary9GSUTgCJ4NbnnoT8
FIELD = map:  org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl$FileItemStreamImpl@54d1ffff
FIELD = file: org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl$FileItemStreamImpl@5a160b15
name? IMG_5327.JPG

When I'm printing the entity it seems like the request is fine:

'------WebKitFormBoundarysmqftmsA0EFDlceo
Content-Disposition: form-data; name="map"

[object Object]
------WebKitFormBoundarysmqftmsA0EFDlceo
Content-Disposition: form-data; name="file"; filename="IMG_5327.JPG"
Content-Type: image/jpeg

Any idea how to solve this? How can I get both the json and the file from the same request?

Eddy
  • 3,533
  • 13
  • 59
  • 89
  • Dunno, but are you sure that the "[object Object]" in the first part of your multipart request is correct? Looks to me as if .toString has been invoked on the JS side rather than the conversation to JSON function. – Brian Aug 28 '16 at 12:13
  • I tried to use stringify but it changes nothing. I'm pretty sure I'm missing a piece of code on the restlet side to get the 'map' object and then pass it to the code that gets the file. – Eddy Aug 28 '16 at 12:16
  • I don't see the Content-Type of your map form data either. Without it frameworks cannot deduce the content properly. – Brian Aug 28 '16 at 12:19
  • Well, I'm asking for help here. The code on the request (angular) side is supposed to allow for sending both json AND a file. Note the headers: {'Content-Type': undefined} header and the transform function one line above it. – Eddy Aug 28 '16 at 13:12
  • 1
    If you provide an isolated case (a complete setup), I'd be willing to take a closer look. – Brian Aug 28 '16 at 15:59
  • I found a solution and posted it as an answer. Not sure it's the most elegant solution but it works. – Eddy Aug 28 '16 at 19:53

1 Answers1

0

I solved it by sending the json object in the query, and getting it in the restlet by using the HttpServletRequest and pulling the relevant parameter from it.

Looking at the code in the question this is the modification on the angular side:

$http.post(REST_SAVE_MAP_URI + "?map=" + JSON.stringify(map), formData, {...

and in the restlet:

org.restlet.Request restletRequest = getRequest();
HttpServletRequest servletRequest = ServletUtils.getRequest(restletRequest);
String mapJson = servletRequest.getParameter("map"));
Gson gson = new Gson();
Map map = gson.fromJson(servletRequest.getParameter("map"), Map.class);

Everything else on both the restlet and angular side is exactly the same.

Eddy
  • 3,533
  • 13
  • 59
  • 89