jersey-client MessageBodyWriter not found for media type=application/x-www-form-urlencoded

爱⌒轻易说出口 提交于 2019-12-11 04:04:07

问题


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:

  1. 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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!