I have a REST WS implemented using Jersey/Jackson. The method which has been implemented is PUT and it is working fine until i get an empty or null body.
After googling a bit, I realized that it is a known issue and there are couple of work arounds available. One of the work around that i found (and implemented) is using ContentRequestFilter to intercept calls, do basic checks and decide what to do.
But in that case, I have to check if the call is for that specific method. I don't like this since what if the method changes in future ?
What i want is to receive as InputStream instead of parsed JacksonObject (Its a custom POJO object created using Jackson Annotations) and parse the inputstream to do that. However, I am unable to find a reference to do that i.e., parsing a jackson object, out of input stream (based on input media type) and return the respective object.
Can someone direct me to some helpful resources or help me here ?
This is an easy way of getting the contents from a request handled by Resource. Just replace Map.class with your annotated POJO:
#POST
public void handle(String requestBody) throws IOException {
ObjectMapper om = new ObjectMapper();
Map result = om.readValue(requestBody, Map.class);
}
With this approach you are free to handle a null value in any way you find suitable.
Related
I'm trying to use one api that in the response body we have this structure:
{"flag": false,
"codes":[
"a3f2b9ddf8886b04993632"]}
At Postman, and executing a curl, the response is exactly this one.
But when I use restTemplate.exchange(...) to return the response body,it's always returning for codes: [[object Object]]
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(URL...); //cannot show partner's url here
header.add("Accept", MediaType.APPLICATION_JSON_VALUE);
header.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
ResponseEntity<String> resourceHttpEntity = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
new HttpEntity<>(header), String.class); //header also has an authorization bearer token that is in another class
System.out.println(resourceHttpEntity.getBody());
Response body from this:
{"flag":false,"codes":["[object Object]"]}
I saw some examples that this occurs, but in Javascript, and we use JSON.stringfy to solve it.
But at Java we don't have this option. I don't know if is a miss-configuration or something.
Even I try to get this response body with the class model using String[], ArrayList for this property. Tried to convert in String.class, JSonNode.class, and it's returning this way.
I tried to use objectMapper to convert, and even test with HTTPURLConnection to confirm and it's happening the same thing. I have the same result.
Any suggestions?
If you need to print the content of a generic object in Json format you can print it as follow:
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
System.out.println(ow.writeValueAsString(object));
// Or better log.info(ow.writeValueAsString(object);
If you don't need to format your output you can call directly writeValueAsString on the objectMapper:
Method that can be used to serialize any Java value as a String
System.out.println(new ObjectMapper().writeValueAsString(object));
Updated answer after the update on the question.
It seems that the remote service that you are invoking is returning exactly the body that you showed in the updated answer.
Your code is treating the body as a simple string, so there is no manipulation on the client-side (your code). It means that is possible that for particular values the server-side (the web service that you are invoking) is performing some strange operation (probably a bean to json conversion) that will generate this output.
You have many ways to check it:
make the same call using postman
make the same call using curl
add a sniffer between your client and the server and use it to log the passing data
For the first two alternatives you have to be sure to use exactly the same data used by the java code. And execute them from the same machine (may be that a proxy can change the behaviour of the call).
We discover that the RestTemplate #Bean that we already have in code, was causing this issue. So I just instantiate a new RestTemplate from scratch, and the issue was resolved.
Thank you for your time.
Create Java class with below attributes and use as response entity type.
Public class Response{
boolean flag;
List<String> codes;
}
ResponseEntity<Response> resourceHttpEntity =
restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
new HttpEntity<>(header), Response.class);
Hello dear Stack Overflow!!! :)
I have a bit of a problem. I am attempting to consume a Hateoas-based application in a project and I'm having issues with Hateoas and it generating a faulty JSON-request for a test. I will provide some code examples!
Basically, I use a JSONconverter that tries to convert my request body(post) to JSON but it throws an error with what I actually get. Some information and code:
Here is my ObjectMapper that I am using:
ObjectMapper objectMapper = (ObjectMapper) bean;
objectMapper.registerModules(new Jackson2HalModule());
Here is my converter config where I plug the objectmapper and the supported media types:
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(Arrays.asList(MediaTypes.HAL_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON_UTF8));
converter.setObjectMapper(objectMapper);
Here is my RestTemplate where I plug the Jackson 2 Http Converter I just made:
#Bean
public RestTemplate uttagRestTemplate(RestTemplateBuilder builder) {
return builder.messageConverters(mappingJackson2HttpMessageConverter, new StringHttpMessageConverter(Charset.forName("UTF-8")))
Here is the test I run with the output:
mockServer.expect(requestTo(url + "/person/" + id + "/links")).andExpect(header("Content-type", MediaType.APPLICATION_JSON_UTF8.toString()))
.andExpect(header("accept", MediaType.APPLICATION_JSON_UTF8.toString()))
.andExpect(content().string(jsonConverter.toJson(Arrays.asList(link)))).andExpect(method(HttpMethod.POST)).andRespond(withSuccess());
Finally, here is my test output(don't mind the data, it's just test data):
Expected :[{"id":2112,"rel":"EZyb","href":"dspK0XickvvcMw0","type":"RaAmwWkZHlagrcQ","length":992539719,"title":"OuaRoPRClRpvprg"}]
Actual :"[{\"id\":2112,\"rel\":\"EZyb\",\"href\":\"dspK0XickvvcMw0\",\"type\":\"RaAmwWkZHlagrcQ\",\"length\":992539719,\"title\":\"OuaRoPRClRpvprg\"}]"
It seems to do something really weird with the "actual" json-generated body. I'd like to have it match my expected, but no luck.
I've tried solving this, and if I remove the MediaType.HAL_JSON from my MappingJacksonConverter somehow it works in my tests, but then I can't consume the hateoas client. I need the media type there for it to work.
I've also tried writing my expected JSON with my MappingJackson writer, but it produces the exact same expected output.
Does anybody know what's going on here and can help me with this? Do you know how I may generate correct JSON-body to get the assert to work? Frankly it's doing my head in - and choosing between functioning tests without the media type and being able to consume the hateoas application with it obviously isn't an option for me. :(
Cheers for reading if you made it this far! :) Any pointers are welcome.
I figured out what it was. With the new config, it seems that the application automatically converts to json and I didn't need to use my own jsonConverter anymore. So what was going on as basically a toJson conversion on an already jsonified object.
After removing my own jsonconverter implementation, it now functions correctly.
I want to be able to invoke a certain method depending on the Accept type in the header of the GET request. Currently, I have the following in my resource class:
import org.restlet.resource.Get;
#Get("json")
public Representation getJson(Variant variant) throws Exception{
return new StringRepresentation("json");
}
#Get("xml")
public Representation getXml(Variant variant) throws Exception {
return new StringRepresentation("xml");
}
#Get("x-octet-stream")
public Representation getFile(Variant variant) throws Exception {
return new StringRepresentation("octet-stream");
}
I can successfully invoke the methods getJson() and getXml() using an http GET with the Accept headers set to application/json and application/xml, repectively. When I issue a GET with the Accept header as application/x-octet-stream, the getJSon() method is invoked instead of the method annotated with x-octet-stream. Do you know why? and/or how I can invoke the getFile() method?
Does Rest only allow you to use json and xml for method entry points? Is there a list of recognized types? I have looked on the site, but there is no said list of anything of that type. Thanks
I believe that the #Get Annotations look up the method in your Application's MetadataService object, using a 'file extension'. See JavaDoc of this class (addCommonExtensions()) for the list of 'file extensions' supported by default.
As a default catch all media type neither application/octet-stream nor it's compressed version have a default mapping. however you are also able to add as many custom mappings and MediaType instances as you would like. I would usually do this as part of my Application set-up, for example:
public Application(final Context context)
{
super(context);
getMetadataService().addExtension("html", MediaType.TEXT_HTML, true);
}
For Completeness: If you are attempting to Download pre-generated files from Disc you may also be interested in looking at using the Directory class.
My service:
#POST
public String setData(#QueryParam("id") Long is, MyObject payload) {
...
}
or
#POST
public String setData(#PathParam("id") Long is, MyObject payload) {
...
}
My interceptor on the server:
Object read(MessageBodyReaderContext context) throws IOException, WebApplicationException {
Class mypayloadtype = context.getType;
InputStream mypayloadinpustream = context.getInputStream();
Long myidparam = ???????? // how to get the query or path param here?
}
EDIT: To be a bit more concrete:
What I'd like to do is to grab the XML and store it based on the parameters in a separate audit system. Maybe PreProcessInterceptor / PostProcessInterceptor are the better choices?
Any hints or alternative ways to get the param when the xml is still available for preprocessing?
Miguel
I just stumbled over the same problem today. I needed the #PathParams and #QueryParams in the read() method and ended up with something like this:
public class MyInterceptor implements PreProcessInterceptor, MessageBodyReaderInterceptor
{
private static ThreadLocal<UriInfo> uri = new ThreadLocal<UriInfo>();
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
{
uri.set(request.getUri);
...
}
public Object read(MessageBodyReaderContext context)
{
String param = uri.get().getPathParameters().getFirst("myidparam");
...
}
}
Although when thinking about it now - I'm not quite sure, if just using PreProcessInterceptor/PostProcessInterceptor will also do the trick for my (and maybe your) problem. I'll have another look tomorrow.
I am not an expert on the topic but to me it seems as if the MessageBodyReaderContext interface does not really know if it is on the server or the client side, so it cannot expose the request or its parameters / path parts etc.
So as far as I know this is not possible.
If your code knows that it lives on the server side of the rest
communication, maybe you can use a servlet filter to store the request
in a ThreadLocal and then access it from there while the request is
handled, somewhat similar to RequestContextFilter / RequestContextHolder from the spring framework? (Then the request object does not know anything about the annotations of your service, but instead one has to extract the information manually from the request. This means to have the same information in two places, so there has to be a better solution ...)
Edit: after looking at some examples I get the vague feeling that if you want to read the input stream to create an object and add path parameters to it, MessageBodyReaderInterceptor is simply not the way to go. Instead set up a MessageBodyReader which constructs the object from the request body data, and this then will be passed into the public String setData(#PathParam("id") Long is, MyObject payload), assuming that this method is annotated with a #Consumes which matches the #ConsumeMime annotation for the MessageBodyReader. There you might be able in the setData to set the missing id on the object read from the request body. Some examples related to this seem to be here: How to get full REST request body using Jersey? (but for Jersey, not jBoss :-/)
However I am not sure if that works for you, and I also feel I completely overestimated my ability to answer this question appropriately, so I hope someone more knowledgeable comes in with a better solution.
Currently our application uses GWT-RPC for most client-server communication. Where this breaks down is when we need to auto generate images. We generate images based on dozens of parameters so what we do is build large complex urls and via a get request retrieve the dynamically built image.
If we could find a way to serialize Java objects in gwt client code and deserialize it on the server side we could make our urls much easier to work with. Instead of
http://host/page?param1=a¶m2=b¶m3=c....
we could have
http://host/page?object=?JSON/XML/Something Magicical
and on the server just have
new MagicDeserializer.(request.getParameter("object"),AwesomeClass.class);
I do not care what the intermediate format is json/xml/whatever I just really want to be able stop keeping track of manually marshalling/unmarshalling parameters in my gwt client code as well as servlets.
Use AutoBean Framework. What you need is simple and is all here http://code.google.com/p/google-web-toolkit/wiki/AutoBean
I've seen the most success and least amount of code using this library:
https://code.google.com/p/gwtprojsonserializer/
Along with the standard toString() you should have for all Object classes, I also have what's called a toJsonString() inside of each class I want "JSONable". Note, each class must extend JsonSerializable, which comes with the library:
public String toJsonString()
{
Serializer serializer = (Serializer) GWT.create(Serializer.class);
return serializer.serializeToJson(this).toString();
}
To turn the JSON string back into an object, I put a static method inside of the same class, that recreates the class itself:
public static ClassName recreateClassViaJson(String json)
{
Serializer serializer = (Serializer) GWT.create(Serializer.class);
return (ClassName) serializer.deSerialize(json, "full.package.name.ClassName");
}
Very simple!