0

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?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
António Ribeiro
  • 4,129
  • 5
  • 32
  • 49
  • 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](http://docs.jboss.org/resteasy/docs/3.0.17.Final/userguide/html/RESTEasy_Embedded_Container.html) to see examples of RESTEasy being run in standalone mode. With RESTEasy, you won't need to register the provider – Paul Samsotha Jun 08 '16 at 14:14
  • Here's a [complete example](http://stackoverflow.com/a/32491802/2587435) 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](http://mvnrepository.com/artifact/org.jboss.resteasy/resteasy-undertow) is the only one you need. – Paul Samsotha Jun 08 '16 at 14:44
  • @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? – António Ribeiro Jun 09 '16 at 07:35
  • 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](https://github.com/resteasy/Resteasy/tree/3.0.x/jaxrs/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 Jun 09 '16 at 07:47
  • If you want to stick with Jersey, you may want to look at [this](https://github.com/resteasy/Resteasy/blob/3.0.x/jaxrs/providers/multipart/src/main/resources/META-INF/services/javax.ws.rs.ext.Providers). 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 Jun 09 '16 at 07:49
  • You might also want to check the link at the bottom of [this](http://docs.jboss.org/resteasy/docs/3.0.17.Final/userguide/html/CDI.html). It has an example to set up CDI with Undertow. Whether will work with RESTEasy, I'm not sure. – Paul Samsotha Jun 09 '16 at 08:02
  • @peeskillet, I followed your advice and switched to the `SunHttpJaxrsServer` embedded server . Also, I managed to enable RESTEasy's CDI extension on it. Perhaps I could place it as an answer for future help. What do you think? – António Ribeiro Jun 09 '16 at 09:45
  • Yeah you should. I personally would like to see how you got it to work :-) – Paul Samsotha Jun 09 '16 at 09:49

1 Answers1

1

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.

Community
  • 1
  • 1
António Ribeiro
  • 4,129
  • 5
  • 32
  • 49