0
votes

I'm developing a set of REST services, using RESTEasy and WildFly 9.0.2.

One of them allows me to upload a file.

@POST
@Path("/upload")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response upload(MultipartFormDataInput input);

I successfully managed to call the REST service and upload the file to the server, so I started to implement the integration tests.

For that, I'm using an embedded Grizzly HTTP server:

@Before
public void setUp() throws Exception {
    // Weld and container initialization
    weld = new Weld();
    weld.initialize();
    ResourceConfig resourceConfig = new ResourceConfig().packages("...");
    server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), resourceConfig);
}

The problem arose when I tried to test the newly created service:

@Test
public void hubbleMapServiceUploadMapTest() throws FileNotFoundException, IOException {
    Client client = null;
    WebTarget webTarget = null;
    Builder builder = null;
    Response response = null;

    try {
        client = ClientBuilder.newBuilder().build();

        webTarget = client.target(BASE_URI).path("/service/upload");
        builder = webTarget.request(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN, MediaType.WILDCARD);

        response = builder.post(Entity.entity(getEntityAsMultipart(), MediaType.MULTIPART_FORM_DATA));

    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        if (response != null) {
            response.close();
        }

        if (client != null) {
            client.close();
        }
    }

    assertNotNull(response);
    assertThat(response.getStatus(), is(Status.OK.getStatusCode()));
}

private GenericEntity<MultipartFormDataOutput> getEntityAsMultipart() {
    String resource = "my.file";
    MultipartFormDataOutput mfdo = new MultipartFormDataOutput();

    try {
        mfdo.addFormData("file",
                new FileInputStream(new File(getClass().getClassLoader().getResource(resource).getFile())),
                MediaType.APPLICATION_OCTET_STREAM_TYPE, resource);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    GenericEntity<MultipartFormDataOutput> entity = new GenericEntity<MultipartFormDataOutput>(mfdo) {
    };

    return entity;
}

The response code is always 415 Unsupported Media Type.

All the remaining integration tests work properly.

What am I doing wrong? Do I need, somehow, to enable Grizzly's Multipart feature?

1
You need to register the multipart provider with Jersey. If you are only using Jersey for testing, you might be better off using RESTEasy. There may be differences in implementations that work in one and not the other. You should take a look at the documentation for embedded containers to see examples of RESTEasy being run in standalone mode. With RESTEasy, you won't need to register the provider - Paul Samsotha
Here's a complete example using the Jdk HttpServer. Only problem is that is doesn't support servlet APIs like HttpServletRequest, if you are using any. For that, you may be better off using the Undertow container. There is an example in the previous comment's link. I think this dependency is the only one you need. - Paul Samsotha
@peeskillet, I really appreciate your inputs! Does any of the mentioned embedded containers allow integration with CDI? For Grizzly, in order to enable CDI, I was using jersey-weld2-se and explicitly initializing weld. Can I do the same for any of the above containers? - aribeiro
Yeah, that's one thing I was looking at that I'm not too sure about I'm not sure how easy it is to integrate CDI as I've never done it. You can look at resteasy-cdi. If you look at the test you can see an example of it being used. Another option is to use Arquillian, which you can run a full EE environment. But it's a more complicated testing framework to learn. - Paul Samsotha
If you want to stick with Jersey, you may want to look at this. This is the list of all providers automatically registered with RESTEasy for multipart support. Whether you need to register all of them, and whether they will all work in Jersey, I am not sure. But you can play around with registering them - Paul Samsotha

1 Answers

1
votes

After following @peeskillet's advice, I switched to Sun JDK HTTP Server embedded server with CDI awareness.

To accomplish that, one needs to do the following:

  1. Add RESTEasy's and WELD necessary Maven dependencies:

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jdk-http</artifactId>
        <version>3.0.17.Final</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-cdi</artifactId>
        <version>3.0.17.Final</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.jboss.weld.se</groupId>
        <artifactId>weld-se</artifactId>
        <version>2.3.4.Final</version>
        <scope>test</scope>
    </dependency>
    
  2. Configure WELD and RESTEasy CDI extension to be used on Sun JDK HTTP Server's deployment configuration:

    private Weld weld;
    private SunHttpJaxrsServer server;
    
    @Before
    public void setUp() throws Exception {
        // Weld initialization
        weld = new Weld();
        weld.initialize();
    
        // RESTEasy CDI extension configuration
        ResteasyCdiExtension cdiExtension = CDI.current().select(ResteasyCdiExtension.class).get();
        ResteasyDeployment deployment = new ResteasyDeployment();
        deployment.setActualResourceClasses(cdiExtension.getResources());
        deployment.setInjectorFactoryClass(CdiInjectorFactory.class.getName());
        deployment.getActualProviderClasses().addAll(cdiExtension.getProviders());
    
        // Container initialization
        server = new SunHttpJaxrsServer();
        server.setDeployment(deployment);
        server.setPort(8787);
        server.setRootResourcePath("/some-context-root/rest");
        server.getDeployment().getActualResourceClasses().add(MyService.class);
        server.start();
    }
    

In order to know how to configure RESTEasy's CDI extension I relied on @John Ament's NettyTest example.