I have some problems in my application, I send a POST request, but I cannot retrieve the JsonObject in my server, this is the code to send:
String quo = "{\"network\": {\"label\": \"new net 111\",\"cidr\": \"10.20.105.0/24\"}}";
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
JsonParser json = new JsonParser();
JsonObject jo = (JsonObject)json.parse(quo);
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target("http://localhost:7999/jersey/rest/network/"+tenant_id);
Response oj = target.request().accept(MediaType.APPLICATION_JSON)
.header("X-Auth-Token", token)
.post(Entity.json(gson.toJson(jo)));
Trying to retrieve with:
#POST
#Produces(MediaType.APPLICATION_JSON)
#Path("/{tenant_id}")
public String createNetwork(#HeaderParam(value = "X-Auth-Token") String authToken,
#PathParam(value = "tenant_id") String tenant_id,
JsonObject network){
Response response = client.target(NOVA_ENDPOINT+tenant_id)
.request(MediaType.APPLICATION_JSON)
.header("X-Auth-Token", authToken)
.post(Entity.json(gson.toJson(network)));
System.out.println("Hello");
String responseJson = response.readEntity(String.class);
JsonObject network seems to be empty, in fact it doesn't execute the method ("Hello is not printed"), the error I get is "Invalid request body" (because the JsonObject is empty I think)..
What's wrong with my code?
Ok, I understood that the problem is related to Json handling such as I'm using Gson. This is my improved code (simplified version) following users suggestion, but I still have problems..
Client Side:
package openstack;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URI;
public class Post {
public static HttpServer startServer() {
final ResourceConfig resourceConfig = new ResourceConfig()
.packages("openstack")
.register(GsonMessageBodyHandler.class);
return GrizzlyHttpServerFactory.createHttpServer(URI.create("http://localhost:7999/jersey/rest"), resourceConfig);
}
public static void main(String[] args) {
String quo = "{\"keypair\": {\"name\": \"MyKey\"}}";
HttpServer server = startServer();
Client client = ClientBuilder.newClient();
client.register(GsonMessageBodyHandler.class);
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
JsonParser json = new JsonParser();
JsonObject jo = (JsonObject)json.parse(quo);
WebTarget target = client.target("http://localhost:7999/jersey/rest/test/prova");
System.out.println(jo);
Response oj = target.request().post(Entity.json(jo));
String responseString = oj.readEntity(String.class);
System.out.println(responseString);
}
}
Server Side:
package openstack;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
#Path("/test")
public class Test {
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
Parliament parliament = new Parliament();
JsonParser json = new JsonParser();
private final Client client;
public Test() {
client = ClientBuilder.newClient().register(GsonMessageBodyHandler.class);
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/prova")
public Response mymethod(JsonObject keypairsob){
return Response.ok(keypairsob).build();
}
}
I created a GsonMessageBodyHandler.java in my package with the code suggested below by the user peeskillet. Added jersey-container-grizzly2-http.jar to my web-inf/lib (I don't know how to proper use Maven), but still doesn't work.. what am I missing?
In order to convert JSON to a Java type, there is need to for a MessageBodyReader and a MessageBodyWriter implementation to do the conversion to and from. Since you are using JsonObject which is a GSON type, you can see this implementation. There is a problem with the implementation though, as the readFrom method doesn't compile with Jersey 2. Here is the a fixed version
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
#Provider
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public final class GsonMessageBodyHandler implements MessageBodyWriter<Object>,
MessageBodyReader<Object> {
private static final String UTF_8 = "UTF-8";
private Gson gson;
private Gson getGson() {
if (gson == null) {
final GsonBuilder gsonBuilder = new GsonBuilder();
gson = gsonBuilder.create();
}
return gson;
}
#Override
public boolean isReadable(Class<?> type, Type genericType,
java.lang.annotation.Annotation[] annotations, MediaType mediaType) {
return true;
}
#Override
public Object readFrom(Class<Object> type, Type type1, Annotation[] antns,
MediaType mt, MultivaluedMap<String, String> mm, InputStream in)
throws IOException, WebApplicationException {
InputStreamReader streamReader = new InputStreamReader(in, UTF_8);
try {
Type jsonType;
if (type.equals(type1)) {
jsonType = type;
} else {
jsonType = type1;
}
return getGson().fromJson(streamReader, jsonType);
} finally {
streamReader.close();
}
}
#Override
public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return true;
}
#Override
public long getSize(Object object, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
#Override
public void writeTo(Object object, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
OutputStreamWriter writer = new OutputStreamWriter(entityStream, UTF_8);
try {
Type jsonType;
if (type.equals(genericType)) {
jsonType = type;
} else {
jsonType = genericType;
}
getGson().toJson(object, jsonType, writer);
} finally {
writer.close();
}
}
}
Then we just need to register it with both the client and the application. I'm using a standalone test, where you can see the configuration here
final ResourceConfig resourceConfig = new ResourceConfig()
.packages("jersey.stackoverflow.standalone")
.register(GsonMessageBodyHandler.class);
...
Client c = ClientBuilder.newClient();
c.register(GsonMessageBodyHandler.class);
Here is the resource class I used for the test
import com.google.gson.JsonObject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import jersey.stackoverflow.standalone.provider.GsonMessageBodyHandler;
#Path("/gson")
public class GsonResource {
private final Client client;
private static final String BASE_URI = "http://localhost:8080/api/gson";
public GsonResource() {
client = ClientBuilder.newClient().register(GsonMessageBodyHandler.class);
}
#POST
#Path("/proxy")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response proxyPost(JsonObject json) {
Response response = client.target(BASE_URI)
.path("main-resource").request().post(Entity.json(json));
JsonObject fromMainResource = response.readEntity(JsonObject.class);
return Response.created(null /* should be a created URI */)
.entity(fromMainResource).build();
}
#POST
#Path("/main-resource")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response mainResource(JsonObject json) {
return Response.ok(json).build();
}
}
Here's the complete test, which requires this maven dependency
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
import static jersey.stackoverflow.standalone.Main.BASE_URI;
import jersey.stackoverflow.standalone.provider.GsonMessageBodyHandler;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.junit.Test;
public class GsonProviderTest {
public static HttpServer startServer() {
final ResourceConfig resourceConfig = new ResourceConfig()
.packages("jersey.stackoverflow.standalone")
.register(GsonMessageBodyHandler.class);
return GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), resourceConfig);
}
public static Client getClient() {
Client c = ClientBuilder.newClient();
c.register(GsonMessageBodyHandler.class);
return c;
}
#Test
public void testGetIt() {
HttpServer server = startServer();
Client c = getClient();
c.register(GsonMessageBodyHandler.class);
String quo = "{\"network\": {\"label\": \"new net 111\",\"cidr\": \"10.20.105.0/24\"}}";
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
JsonParser json = new JsonParser();
JsonObject jo = (JsonObject) json.parse(quo);
WebTarget target = c.target("http://localhost:8080/api/gson/proxy");
Response response = target.request().post(Entity.json(jo));
String responseString = response.readEntity(String.class);
System.out.println(responseString);
response.close();
c.close();
server.stop();
}
}
All the test does is send the JsonObject. Though there isn't any visible conversion to JSON, in any of my code, it is happening behind the scenes by the GsonMessageBodyHandler. If you look at the GsonResource class, you can see the methods don't do anything but send out the JsonObject. In the client test, I read the response as a String, and you can see the result the same as what sent out in the initial request.
See more about MessageBodyReaders and MessageBodyWriters
There's a simple way to get the JsonObject in com.google.gson.JsonObject type using a post request.
I am assuming that all the dependencies for com.google.gson , jersey and jax-rs are already added.
On the server side you need to have code similar to below :
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
#Path("/api")
public class JersyAPI {
private JsonParser parser= new JsonParser();
#POST
#Path("/pudding")
#Consumes("application/json")
public Response postTest(String requestBody){
Response re = Response.status(200).build();
try{
JsonObject inputObjectJson = parser.parse(requestBody).getAsJsonObject();
The code above has a rest endpoint defined with path /api/pudding and it is accepting the Request Body as String. Once you receive the Json as string on server side, com.google.gson.JsonParser can be used to convert it into the com.google.gson.JsonObject directly and this can be used in your program.
To make a request on server side you post request should look like this :
POST /rest/api/pudding HTTP/1.1
Host: localhost:8082
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: c2b087d9-4830-c8a8-2a19-78273a73898c
{
"id": 1312312,
"name": "Test",
"data": {
"test" : "data"
},
}
Have you had any JSON requests successfully parsed? It could be that you need to enable JSON support in Jersey:
https://jersey.java.net/documentation/1.18/json.html
Otherwise, it may simply be failing on your request to turn the message body into a JsonObject here:
public String createNetwork(
#HeaderParam(value = "X-Auth-Token") String authToken,
#PathParam(value = "tenant_id") String tenant_id,
JsonObject network)
Related
I'm very new to web-service dev and I'm trying to make a POST request to an API using Jersey. The issue is I think I'm mixing documentation and example I'm finding online between client & server. I'm pretty sure that it's simple but I can't figure out why my code is failing.
Here is my main Class :
import deliveryPayload.Payload;
import jakarta.ws.rs.*;
import jakarta.ws.rs.client.*;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import org.apache.commons.lang3.StringUtils;
import responsePayload.ResponsePayload;
import java.net.URI;
import java.util.*;
#Path("/hook")
public class Hook {
private static final String apiToken = "myToken";
private static final String domain = "url";
private static final String apiUrl = "https://" + domain + "/api/v1/";
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response eventHook(String body, #HeaderParam("Pass") String password) {
ObjectMapper objectMapper = new ObjectMapper();
Payload payload = new Payload();
try {
payload = objectMapper.readValue(body, Payload.class);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
EventsItem event = payload.getData().getEvents().get(0);
Actor actor = event.getActor();
Response response = ClientBuilder.newClient()
.target(getBaseURI())
.path("apps/" + "someID" + "/users")
.request(MediaType.APPLICATION_JSON)
.header(HttpHeaders.AUTHORIZATION, apiToken)
.post(Entity.entity(actor, MediaType.APPLICATION_JSON));
return response;
}
}
I'm getting this error Parse Error: The response headers can't include "Content-Length" with chunked encoding when using Postman.
Thanks for any help !
I am getting the error 'A JSONObject text must begin with '{' at 1 [character 2 line 1]'
while calling NewsAPI using RestTemplate of Spring.
Below is the snippet code I have used to get response. I am able to get the response string but unable to parse it through org.JSON class
import java.util.Arrays;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
public class APITest {
final private static String NEWSAPI_URI="https://newsapi.org/v2/top-headlines";
final private static String API_TOKEN_VAL=“*****************”;
final private static String API_TOKEN="apiKey";
final private static String COUNTYRY="Country";
final private static String COUNTYRY_VAL="US";
public static void main(String[] args) {
RestTemplate restTemplate=new RestTemplate();
UriComponentsBuilder builder=UriComponentsBuilder.fromHttpUrl(NEWSAPI_URI)
.queryParam(API_TOKEN, API_TOKEN_VAL)
.queryParam(COUNTYRY, COUNTYRY_VAL)
;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> responseEntity=restTemplate.exchange(builder.toUriString(), HttpMethod.GET, entity, String.class);
//parsing responseEntity
HttpStatus httpStatus=responseEntity.getStatusCode();
String responseString=responseEntity.getBody();
System.out.println(responseString);
if(httpStatus.is2xxSuccessful()) {
JSONObject jsonObject=new JSONObject(responseString.trim());
JSONArray articles=jsonObject.getJSONArray("articles");
//System.out.println(articles.getJSONObject(0).get("content"));
for(int it=0;it<articles.length();it++) {
JSONObject articleObject=articles.getJSONObject(it);
System.out.println(articleObject.getString("content"));
}
}
}
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
I have a sample backend response coming as below:
When I try to map this response into the java object, I am getting following error.
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of com.mc.membersphere.model.MemberSummaryLabel[] out of START_OBJECT token
Seems like the issue with the body tag coming from API. Which has array of objects. I need help, how to handle this body tag arrays value in Java mapping?
Backend API Response:
{
"body": [{
"pcp": "KASSAM, Far",
"er12M": "0",
"ipAdmits12M": "0",
"ipReAdmits12M": "0",
"rx12M": "0",
"pastMedicalHistory": " ",
"erCost12M": "0.0"
}
]
}
Java Program to get the Rest data into the Java objects is as below.
import java.util.Collections;
import java.util.Properties;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import com.mc.membersphere.model.MemberSummaryLabel;
import com.mc.membersphere.utility.PropertyUtil;
public class TestRestclient implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(TestApi.class, args); }
private static Properties prop = PropertyUtil.getProperties();
#Override
public void run(String... args) throws Exception {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String getMVPSummaryUrl = prop.getProperty("getmvpmembersummary.url");
String url = getMVPSummaryUrl+"/"+"CA";
ResponseEntity<MemberSummaryLabel[]> response = restTemplate.exchange(url, HttpMethod.GET,entity, MemberSummaryLabel[].class);
if(response.getStatusCode()== HttpStatus.OK) {
for(MemberSummaryLabel memberSummaryLabel : response.getBody())
{
System.out.println(memberSummaryLabel.pcp);
}
//System.out.println("Print response" + response);
}
else {
System.out.println("Error");
}
}
}
MemberSummaryLabel is as below.
import com.fasterxml.jackson.annotation.JsonProperty;
public class MemberSummaryLabel {
#JsonProperty("pcp")
public String pcp;
#JsonProperty("er12M")
public Integer er12M;
#JsonProperty("ipAdmits12M")
public Integer ipAdmits12M;
#JsonProperty("ipReAdmits12M")
public Integer ipReAdmits12M;
#JsonProperty("rx12M")
public Integer rx12M;
#JsonProperty("pastMedicalHistory")
public String pastMedicalHistory;
#JsonProperty("erCost12M")
public Double erCost12M;
}
I see, its an issue with your mapping. Your response is in "body" and body contains list of MemberSummaryLabel. So, you need to have one more class as mentioned below,
public class Body{
#JsonProperty("body")
public List<MemberSummaryLabel> memberSummaryLabelList;
}
And your exchange method should return NewClass.
ResponseEntity<Body> response = restTemplate.exchange(url, HttpMethod.GET,entity, Body.class);
And for, iteration use,
for(MemberSummaryLabel memberSummaryLabel : response.getBody().getMemberSummaryLabelList()){
}
Edit:
I tried to implement the suggestions of #Durgpal Singh and #Nikhil. I changed the code so it looks like this.
Client:
Client client = ClientBuilder.newClient();
WebTarget target = client
.target("http://localhost:8087/api/ls3algorithm/" + petrinets + "/" + Integer.toString(k) + "/" + Float.toString(theta));
Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.get();
Map<String, List<Map>> result_ = response.readEntity(new GenericType<Map<String, List<Map>>>() { });
result = (ArrayList<Map>) result_.get("data");
Server:
ArrayList<Map> result;
result = new Ls3Algorithm().execute(new File("petrinetze").getAbsolutePath(), k, theta);
Map<String, List<Map>> map = new HashMap<>();
map.put("data", result);
return Response.ok(map).build();
Unfortunately this leads to Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/json, type=interface java.util.Map, genericType=java.util.Map<java.lang.String, java.util.List<java.util.Map>>.
Where do I go wrong?
-------------------------------
I'm pretty new to RESTful web services and currently writing a microservice which provides a calculating algorithm. I'm testing the service as posted below.
Workflow:
Client saves some data in a MongoDB database and sends the names of the relevant files via #PathParam as part of the GET request. The server then retrieves the files from the MongoDB, processes its algorithm and sends back the result as List<Map> packed in a Response object.
Goal:
Transfer the result (List<Map>) as JSON and print it out on the client console.
Client:
package ls3test;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Map;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSInputFile;
public class Ls3TransmissionTest {
final static String petrinets = "eins, zwei, drei, vier";
final static int k = 3;
final static float theta = 0.9f;
public static void main(String[] args) throws IOException {
[... save all the relevant files in the MongoDB ...]
ArrayList<Map> result = new ArrayList<Map>();
Client client = ClientBuilder.newClient();
WebTarget target = client
.target("http://localhost:8087/api/ls3algorithm/" + petrinets + "/" + Integer.toString(k) + "/" + Float.toString(theta));
Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON);
Response response = invocationBuilder.get();
result = response.readEntity(new GenericType<ArrayList<Map>>() {
});
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(result);
}
}
Server:
package service;
import com.fasterxml.jackson.core.JsonGenerationException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.DB;
import com.mongodb.MongoClient;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.GenericEntity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
#SuppressWarnings("deprecation")
#Path("/ls3algorithm")
public class Resource {
// SLF4J is provided with Dropwizard
Logger log = LoggerFactory.getLogger(Resource.class);
#SuppressWarnings("rawtypes")
#GET
#Path("/{petrinets}/{k}/{theta}")
#Produces(MediaType.APPLICATION_JSON)
public Response ls3execute(#PathParam("petrinets") String petrinetNames, #PathParam("k") int k,
#PathParam("theta") float theta) {
[... get all the relevant files from the MongoDB ...]
List<Map> result;
Ls3Algorithm ls3Algorithm = new Ls3Algorithm();
result = ls3Algorithm.execute(new File("petrinetze").getAbsolutePath(), k, theta);
GenericEntity<List<Map>> entity = new GenericEntity<List<Map>>(result) {};
Response response = Response.ok(entity).build();
return response;
}
}
This is not working, the exception I get is posted below:
Exception in thread "main" org.glassfish.jersey.message.internal.MessageBodyProviderNotFoundException: MessageBodyReader not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.ArrayList<java.util.Map>.
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:231)
at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:874)
at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:834)
at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:368)
at org.glassfish.jersey.client.InboundJaxrsResponse$2.call(InboundJaxrsResponse.java:126)
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:419)
at org.glassfish.jersey.client.InboundJaxrsResponse.runInScopeIfPossible(InboundJaxrsResponse.java:267)
at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:123)
at ls3test.Ls3TransmissionTest.main(Ls3TransmissionTest.java:89)
Ls3TransmissionTest.java:89 is ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
I spent plenty of time now doing research on this problem, but I cannot find an example that really fits it. What do I miss? Any help or hint is highly appreciated!
You can send a map. Like this
Map<String, Object> map = new HashMap<>();
map.put("data", entity);
Response.ok(map).build();
return Response;
Cannot see why do you need to wrap the List with GenericEntity. Something as simple as below will work:-
#SuppressWarnings("rawtypes")
#GET
#Path("/{petrinets}/{k}/{theta}")
#Produces(MediaType.APPLICATION_JSON)
public Response ls3execute(#PathParam("petrinets") String petrinetNames, #PathParam("k") int k,
#PathParam("theta") float theta) {
//[... get all the relevant files from the MongoDB ...]
List<Map> result;
Ls3Algorithm ls3Algorithm = new Ls3Algorithm();
result = ls3Algorithm.execute(new File("petrinetze").getAbsolutePath(), k, theta);
Response response = Response.ok(result).build();
return response;
}
And in the client side,
String result = response.readEntity(String.class);
return result;
How can one get the full HTTP REST request body for a POST request using Jersey?
In our case the data will be XML. Size would vary from 1K to 1MB.
The docs seem to indicate you should use MessageBodyReader but I can't see any examples.
Turns out you don't have to do much at all.
See below - the parameter x will contain the full HTTP body (which is XML in our case).
#POST
public Response go(String x) throws IOException {
...
}
You could use the #Consumes annotation to get the full body:
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
#Path("doc")
public class BodyResource
{
#POST
#Consumes(MediaType.APPLICATION_XML)
public void post(Document doc) throws TransformerConfigurationException, TransformerException
{
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.transform(new DOMSource(doc), new StreamResult(System.out));
}
}
Note: Don't forget the "Content-Type: application/xml" header by the request.
Try this using this single code:
import javax.ws.rs.POST;
import javax.ws.rs.Path;
#Path("/serviceX")
public class MyClassRESTService {
#POST
#Path("/doSomething")
public void someMethod(String x) {
System.out.println(x);
// String x contains the body, you can process
// it, parse it using JAXB and so on ...
}
}
The url for try rest services ends .... /serviceX/doSomething
Since you're transferring data in xml, you could also (un)marshal directly from/to pojos.
There's an example (and more info) in the jersey user guide, which I copy here:
POJO with JAXB annotations:
#XmlRootElement
public class Planet {
public int id;
public String name;
public double radius;
}
Resource:
#Path("planet")
public class Resource {
#GET
#Produces(MediaType.APPLICATION_XML)
public Planet getPlanet() {
Planet p = new Planet();
p.id = 1;
p.name = "Earth";
p.radius = 1.0;
return p;
}
#POST
#Consumes(MediaType.APPLICATION_XML)
public void setPlanet(Planet p) {
System.out.println("setPlanet " + p.name);
}
}
The xml that gets produced/consumed:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<planet>
<id>1</id>
<name>Earth</name>
<radius>1.0</radius>
</planet>
It does seem you would have to use a MessageBodyReader here. Here's an example, using jdom:
import org.jdom.Document;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.MediaType;
import javax.ws.rs.ext.MultivaluedMap;
import java.lang.reflect.Type;
import java.lang.annotation.Annotation;
import java.io.InputStream;
#Provider // this annotation is necessary!
#ConsumeMime("application/xml") // this is a hint to the system to only consume xml mime types
public class XMLMessageBodyReader implements MessageBodyReader<Document> {
private SAXBuilder builder = new SAXBuilder();
public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {
// check if we're requesting a jdom Document
return Document.class.isAssignableFrom(type);
}
public Document readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) {
try {
return builder.build(entityStream);
}
catch (Exception e) {
// handle error somehow
}
}
}
Add this class to the list of resources your jersey deployment will process (usually configured via web.xml, I think). You can then use this reader in one of your regular resource classes like this:
#Path("/somepath") #POST
public void handleXMLData(Document doc) {
// do something with the document
}
I haven't verified that this works exactly as typed, but that's the gist of it. More reading here:
http://weblogs.java.net/blog/mhadley/archive/2008/02/integrating_jer_2.html
http://blogs.oracle.com/sandoz/entry/jersey_and_abdera_with_a