MessageBodyWriter not found for media type=multipart/form-data in JerseyTest
Asked Answered
G

1

12

I'm trying to create a test for a POST method in a resource class in a Jersey program.

Here's the POST method of the resource:

@POST @Path("/new")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public Response HTTPPostMethod(@FormDataParam("file") InputStream fileIS, 
                           @FormDataParam("file") FormDataContentDisposition contentDispositionHeader) {
    // ... some code that handles the InputStream
}

My ResourceConfig is created in the following way:

public class MyApp extends ResourceConfig {

    public MyApp(String param) {
        register(createMoxyJsonResolver());     
        register(MultiPartFeature.class);
        register(MyResource.class);
    }

     private static ContextResolver<MoxyJsonConfig> createMoxyJsonResolver() {
        final MoxyJsonConfig moxyJsonConfig = new MoxyJsonConfig();
        Map<String, String> nsPrefixManager = new HashMap<String, String>(1);
        nsPrefixManager.put("http://www.w3.org/2001/XMLSchema-instance", "xsi");
        moxyJsonConfig.setNamespacePrefixMapper(nsPrefixManager).setNamespaceSeparator(':');
        return moxyJsonConfig.resolver();
    }

    /**
     * Start the Grizzly HTTP Server
     * 
     */
    public final void startHttpServer(int port) {
        try {
            final String url = "http://localhost:" + port + "/myapp";
            final HttpServer server = 
                    GrizzlyHttpServerFactory
                        .createHttpServer(URI.create(url), this);

            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                public void run() {
                    server.shutdown();
                }
            }));
            Thread.currentThread().join();

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)  {
        try {
            final MyApp app = new MyApp(args[1]);
            int port = Integer.parseInt(args[0]);
            app.startHttpServer(port);
        } catch(NumberFormatException e) {
            e.printStackTrace();
        }
    }
}

My jersey test setup:

public class TestBase extends JerseyTest {

    protected Application app;
    protected static final String param = "myparam";

    @Override
    protected Application configure() {
        // The MultiPartFeature is registered.
        this.app = new MyApp(param);
        return app;
    }
}

Finally, the test that's causing problems:

public class MyResourceTest extends TestBase {

// ...

    @Test
    public void testHTTPPost() {

        try {

            FileDataBodyPart filePart = new FileDataBodyPart("file", new File("path/to/a/file/i/know/exists"));
            FormDataMultiPart formDataMultipart = new FormDataMultiPart();
            FormDataMultiPart multipart = (FormDataMultiPart)formDataMultipart.bodyPart(filePart);

            Response result = target("/myResource/new").request().post(Entity.entity(multipart, multipart.getMediaType()));
            formDataMultipart.close();
            multipart.close();

            assertEquals(Response.Status.OK.getStatusCode(), result.getStatus());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

// ...

}

I'm always getting the error:

org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=multipart/form-data, type=class org.glassfish.jersey.media.multipart.FormDataMultiPart, genericType=class org.glassfish.jersey.media.multipart.FormDataMultiPart.
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:247)
    at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1130)
    at org.glassfish.jersey.client.ClientRequest.writeEntity(ClientRequest.java:502)
    at org.glassfish.jersey.client.internal.HttpUrlConnector._apply(HttpUrlConnector.java:388)
    at org.glassfish.jersey.client.internal.HttpUrlConnector.apply(HttpUrlConnector.java:285)
    at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:255)
    at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
    at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
    at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:343)
    at services.MyResourceTest.testHTTPPost(MyResourceTest.java:151)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
    at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
    at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
    at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
    at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
    at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
    at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

I tried the following code in the TestBase, but it didn't work:

@Override
    protected Application configure() {
        ResourceConfig app = new ResourceConfig();
        app.register(MultiPartFeature.class);
        app.register(MyResource.class);
        this.app = app;
        return app;
    }

Same error. What am I doing wrong here?

Ginkgo answered 29/2, 2016 at 14:17 Comment(1)
This is similar to #19668926Edenedens
S
14

The MultiPartFeature register the required MessageBodyWriter/MessageBodyReader to handle multipart. You have it registered on the server (which will use the reader to deserialize the inbound request entity), but you also need to register it on the client (which uses the writer to serialize the outbound request entity).

There are actually a few places where you can register it. A couple are with the WebTarget or with the Client. If you want to register it with the client, you can override configureClient(ClientConfig) in the JerseyTest

@Override
public void configureClient(ClientConfig config) {
    config.register(MultiPartFeature.class);
}

Or, with the WebTarget, you can simply do

target(...).register(MultiPartFeature.class)..
Schroer answered 29/2, 2016 at 14:24 Comment(1)
Thanks! Accepting in a minute. Did the configureClient method and got it working.Ginkgo

© 2022 - 2024 — McMap. All rights reserved.