Reputation: 364
I am creating my first web service,so it might be that I am missing something very simple. I created a web service in Eclipse Kepler using Jersey 2.x without Maven on Tomcat and it is working for "@GET" requests without parameters (tested from browser and client application), but I am having problems with a "@POST" (the code is bellow). This is actually a get request with a very complex filtering conditions.
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public String getFilteredPictures(ArrayList<FilterOption> filters)
{
PictureProvider provider = new PictureProvider();
ArrayList<PictureInfo> pictures;
try
{
pictures = provider.getPictures(filters);
Gson gson = new Gson();
return gson.toJson(pictures);
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
I created a dummy client, just to see that the method above is working:
HttpClient httpclient = new DefaultHttpClient();
Gson gson = new Gson();
HttpPost request = new HttpPost(SERVICE_URI + picturesServiceEndPoint);
//create dummy data
ArrayList<FilterOption> filters = new ArrayList<>();
ArrayList<String> options = new ArrayList<>();
options.add("Black");
filters.add(new FilterOption("Color", options));
StringEntity postParam = StringEntity(gson.toJson(filters), "UTF-8");
postParam.setContentType("application/json");
request.setEntity(postParam);
request.setHeader("Accept", "application/json");
try
{
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null)
{
//obtain results..
}
}
catch (ClientProtocolException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
When I run the client the server throws the following exception ".MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/json":
I suspect the problem is that it can not convert JSON to my POJO object so I put an init param in my web.xml, but it had no effect. In addition, I tried sending just a FilterOption object, thinking that ArrayList is too complex, but again it had no effect.
Thank you for your time:)
Upvotes: 1
Views: 5362
Reputation: 4246
A typical cause of the MessageBodyProviderNotFoundException
is that the class you are trying to serialize to JSON is not properly formed.
In my case, I was missing a no-argument constructor. After I added an empty no-argument constructor, everything just worked.
Upvotes: 1
Reputation: 5443
Jersey JSON support comes as a set of extension modules where each of these modules contains an implementation of a Feature
that needs to be registered into your Configurable
instance (client/server). There are multiple frameworks that provide support for JSON processing and/or JSON-to-Java binding. The modules listed below provide support for JSON representations by integrating the individual JSON frameworks into Jersey. At present, Jersey integrates with the following modules to provide JSON support:
for more information read chapter 9 of jersey documentation.
Moxy is the proposed method for json media support. MOXy media module is one of the modules where you don't need to explicitly register it's Features (MoxyJsonFeature) in your client/server Configurable as this feature is automatically discovered and registered when you add jersey-media-moxy module to your class-path.
To use MOXy as your JSON provider you need to add jersey-media-moxy module to your pom.xml file:
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.15</version>
</dependency>
If you're not using Maven make sure to have all needed dependencies. see jersey-media-moxy dependencies.
You need to add these jar file to your project in order to support json media types via jersey-media-moxy:
some ordinary class:
public class MyJAXBBean{
private String name = "jack";
private int id = 12;
public MyJAXBBean() {
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
}
And a main class for running a jersey client example:
public static void main(String[] args) {
//ClientConfig cc = new ClientConfig().register(new JacksonFeature());
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8084/myhost/test");
Form form = new Form();
form.param("x", "foo");
form.param("y", "bar");
MyJAXBBean bean;
bean = target.request(MediaType.APPLICATION_JSON_TYPE)
.post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE),
MyJAXBBean.class);
System.out.println(bean);
}
the json response of the server(http://localhost:8084/myhost/test
) must be in the following format:
{"name":"haleh", "id":3}
Upvotes: 1
Reputation: 3156
You can still preserve the signatures of your methods, the media-type, and still use GSON to marshal/unmarshal, by implementing the 2 interfaces MessageBodyWriter, and MessageBodyReader.
I don't have a code sample of my own project at hand, but the following looks good : http://eclipsesource.com/blogs/2012/11/02/integrating-gson-into-a-jax-rs-based-application/
Upvotes: 1
Reputation: 364
I found a way to avoid the expected solution. I am simply working with Strings and parse them with gson library:
@POST
// @Consumes(MediaType.APPLICATION_JSON)
// @Produces(MediaType.APPLICATION_JSON)
public String getFilteredPictures(String jsonFilters)
{
PictureProvider provider = new PictureProvider();
ArrayList<PictureInfo> pictures = null;
ArrayList<FilterOption> filters = null;
if (jsonFilters != null)
{
Type collectionType = new TypeToken<ArrayList<FilterOption>>()
{}.getType();
filters = gson.fromJson(jsonFilters, collectionType);
}
.....
Upvotes: 1
Reputation:
JAX-RS can only convert JSON to and from a FilterOption
instance if you tell it how to do this.
A common way is to use JAXB for this:
@XmlRootElement
class FilterOption {
// members, getters, setters, constructors
}
Upvotes: 0