Search code examples
javahttpjerseymultipartform-datadropwizard

Jersey FormDataParam fails with 400 Bad Request


I have a very weird behaviour from Jersey and FormDataParam when trying to upload an image to my service. My service runs on Dropwizard.

The method that accepts an image (along with metadata object) looks like this:

    @POST
    @Path("/photos")
    @Consumes("multipart/form-data")
    fun upload(
        @FormDataParam("photo") fileInputStream: FileInputStream,
        @FormDataParam("metadata") metadata: PhotoMetadataV1RequestModel
    ) {
        // do something
    }

I've registered MultipartFeature in the Guice module.

public class JerseyModule extends AbstractModule {

    @Override
    protected void configure() {
        // other stuff

        bind(MultiPartFeature.class).in(Scopes.SINGLETON);
    }

}

I've added a jersey-multipart dependency in the build.gradle.

    // Jersey
    compile "org.glassfish.jersey.core:jersey-server:$jerseyVersion"
    compile "org.glassfish.jersey.media:jersey-media-multipart:$jerseyVersion"

Now the funny part.

This actually works if I try to upload a file using an absolute path! BUT, it does NOT work I try to upload a file using a relative path.

More importantly, it also does NOT work when a service is deployed on another machine (not the same the upload image request is coming from). This is important, because I deploy my service to Heroku, and I need to upload images from other places!

This is what works (absolute path for the photo):

curl --location --request POST "http://localhost:8095/rest/v1/self/photos" \
--header "Authorization: Bearer GaKC8xQju5h" \
--form 'photo=/Users/whizzil/Desktop/nova_scripts/create_users/user-lina/photos-webp/photo-profile-1.webp' \
--form 'metadata={"photoType": "PROFILE", "position": 2};type=application/json' 

However, even this does NOT work if the url of the server is not localhost, but e.g. Heroku server.

This is what does NOT work (relative path for the photo):

curl --location --request POST "http://localhost:8095/rest/v1/self/photos" \
--header "Authorization: Bearer GaKC8xQju5h" \
--form 'photo=@./photo-profile-1.webp' \
--form 'metadata={"photoType": "PROFILE", "position": 2};type=application/json'

The exception that is thrown when it doesn't work:

org.glassfish.jersey.internal.inject.ExtractorException: org.glassfish.jersey.internal.inject.ExtractorException: java.io.FileNotFoundException: Invalid file path
org.glassfish.jersey.media.multipart.FormDataParamException: HTTP 400 Bad Request
    at org.glassfish.jersey.media.multipart.internal.FormDataParamValueFactoryProvider$FormDataParamValueFactory.provide(FormDataParamValueFactoryProvider.java:352)
    at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:90)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)

I am lost here. I tried googling everything, but no success. Any help much appreciated!


Solution

  • Changing FileInputStream to InputStream solved the issue. I have no idea why, though.