riotvan riotvan - 4 months ago 38
Java Question

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

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?

Answer

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)..
Comments