问题
Using org.glassfish.jersey.core.jersey-client version 2.16 and can't seem to make a simple POST request:
MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/x-www-form-urlencoded
client
String response = ClientBuilder.newClient().target("http://0.0.0.0:8080")
.path("/get")
.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(getForm(), MediaType.APPLICATION_FORM_URLENCODED_TYPE), String.class);
private Form getForm()
{
return new Form() {{ this.param("whatever", "whatever"); }};
}
server
@Path("/get")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public String postForToken(@FormParam("whatever") final String whatever) {...}
Registering a MultiPartFeature as per this post makes no difference.
config.register(MultiPartFeature.class);
回答1:
Ok, so the clue was in the full exception message (not posted above).
org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyWriter not found for media type=application/x-www-form-urlencoded, type=class com.blah.AcceptanceTest$1, genericType=class com.blah.AcceptanceTest$1.
The $1 indicates it's trying to resolve some sort of inner class - which led me to the anonymous subclass of Form. Changing the above to the following works fine:
private Form getForm()
{
final Form form = new Form();
form.param("whatever", "whatever");
return form;
}
回答2:
Jersey uses Entity Providers to serialize and de-serialize Java objects — it uses MessageBodyWriter
to serialize and MessageBodyReader
to de-serialize. Some entity providers are available out-of-the-box, including the FormProvider
, which handles both reading and writing of Form
objects that are of media type application/x-www-form-urlencoded
.
Section 8.3 of the Jersey documentation outlines the algorithm used when deciding which registered Provider to use. Step 5 says this:
- Iterate through the sorted MessageBodyWriter providers and, utilizing the isWriteable method of each until you find a MessageBodyWriter that returns true.
The problem is that the implementation of isWriteable() in FormProvider
checks to see if the runtime type of the object is exactly equal to Form.class
-- subclasses, including anonymous classes, do not qualify, so the method returns false
and the FormProvider
is not used for serialization. Then, no other matching providers are found, and the result is a MessageBodyProviderNotFoundException
.
The Easy Solution:
The easy solution is to just use an actual Form
class.
The Hard Solution:
For anyone who really wants to use subclasses of Form
, the hard solution would be to reimplement FormProvider
(it's marked final
, so you can't just subclass it), substituting the following code for the isWriteable()
method:
public boolean isWriteable(...) {
return Form.class.isAssignableFrom(type);
}
Then you'd have to register your custom FormProvider with the Client
before you use it:
Client client = ClientBuilder.newClient().register(MyFormProvider.class);
来源:https://stackoverflow.com/questions/28969110/jersey-client-messagebodywriter-not-found-for-media-type-application-x-www-form