Using Jackson to parse multipart/form-data or application/json - java

I am using CXF with JacksonJsonProvider for my REST Services. I have a test method as follows
#POST
#Path("/book/{id}")
#Consumes({"application/json, multipart/form-data, application/x-www-urlencoded"})
#Produces({"application/json"})
public boolean setOwner(Book book) {
System.out.println(book.getName());
return true;
}
Now if I make a POST request with a raw JSON string as follows
{"Book":{"name":"Book name","publisher":"Book publisher"}}
The request is processed correctly as I use Content-Type as 'application/json' while making the request.
But since I am integrating with an external service, I recieve either multipart/form-data OR application/x-www-urlencoded for which there is nothing afaik in Jackson that can handle it. If someone can point me to the right direction that would be great.
I can manage multipart/form-data with Jettison (part of CXF) but I would like to use Jackson.

I was looking to do exactly the same thing, almost to years later! I didn't have much luck using one method to handle multiple mime times, but I did get it to work using two methods, for example:
#POST
#Path("/book/{id}")
#Consumes({"multipart/form-data"})
#Produces({"application/json"})
public boolean setOwnerFromUpload(#FormDataParam("file") InputStream inputStream) {
// decode
final ObjectMapper mapper = new ObjectMapper();
final Book book = (Book) mapper.readValue(inputStream, Book.class);
System.out.println(book.getName());
return true;
}
With two methods, jackson can now handle the the two different mime types.

Related

How a rest API will return both Json and XML response depending on the input header?

The code is as follow.Where I am checking the content type extracted from the header then I want to write the code and return the response from the same method.
#POST
#Produces(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_XML)
public Response addMessage(Message message , #Context UriInfo uriInfo,
#HeaderParam ("content-type") String contentType) throws
URISyntaxException
{
//Conditional check based on the content type.
if(contentType.equals("application/json")) {
return json;
}else {
return xml;
}
}
How a rest API will return both Json and XML response depending on the input header?
First , your usage of multiple #Produces on same method is incorrect. A String[] can be specified for all types that you wish to produce with #Produces , Annotation Type Produces
And for your main question, I agree with vlumi's comment that ,
You should just return the Response built with the object to return,
and let JAX-RS handle the serialization into XML or JSON, depending on
which the client expects/prefers
i.e. let the framework do it for you depending on Accept header as specified by client as Raj has already mentioned in comments,
You have to pass the request header Accept: application/json or
application/xml
Jersey Multiple Produces

How to pass a json object as a parameter in a REST request URL with Springboot

I have looked at the various answers and they do not resolve my issue. I have a very specific client need where I cannot use the body of the request.
I have checked these posts:
Trying to use Spring Boot REST to Read JSON String from POST
Parsing JSON in Spring MVC using Jackson JSON
Pass JSON Object in Rest web method
Note: I do encode the URI.
I get various errors but illegal HTML character is one. The requirement is quite simple:
Write a REST service which accepts the following request
GET /blah/bar?object=object11&object=object2&...
object is a POJO that will come in the following JSON format
{
"foo": bar,
"alpha": {
"century": a,
}
}
Obviously I will be reading in a list of object...
My code which is extremely simplified... as below.
#RequestMapping(method=RequestMethod.GET, path = "/test")
public Greeting test(#RequestParam(value = "object", defaultValue = "World") FakePOJO aFilter) {
return new Greeting(counter.incrementAndGet(), aFilter.toString());
}
I have also tried to encapsulate it as a String and convert later which doesnt work either.
Any suggestions? This should really be extremely simple and the hello world spring rest tut should be a good dummy test framework.
---- EDIT ----
I have figured out that there is an underlying with how jackson is parsing the json. I have resolved it but will be a write up.. I will provide the exact details after Monday. Short version. To make it work for both single filter and multiple filters capture it as a string and use a json slurper
If you use #RequestParam annotation to a Map<String, String> or MultiValueMap<String, String> argument, the map will be populated with all request parameters you specified in the URL.
#GetMapping("/blah/bar")
public Greeting test(#RequestParam Map<String, String> searchParameters) {
...
}
check the documentation for a more in depth explanation.

Get JSON message in JAX-RS web service filter

I have a web service method as follow (deployed on WebLogic 12.2.1), which I can receive the JSON request body in the POJO object "requestParameters":
#POST
#SessionChecker
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("LogIn")
public Response logIn(#Context HttpServletRequest request, Parameters requestParameters) {
....
}
I have a filter that I want to intercept the request before the above web service method is called.
#Provider
#SessionChecker
public class CheckSessionFilter implements ContainerRequestFilter {
#Context
private HttpServletRequest servletRequest;
#Override
public void filter(ContainerRequestContext requestContext) throws WebApplicationException {
....
}
}
In the filter() method, how do I get the JSON message body into the POJO object of type Parameters? I just need to get one attribute from the JSON message. After the filter is done, the JSON message should pass on to the web service method without change.
Thanks in advance.
Here's the problem. When your filter is hit, the request stream (InputStream) hasn't been read yet. So if you try to read it, then Jersey will not be able to read it, as a stream can only be read once, so it will be empty.
Jersey actually offers a solution to this. The ContainerRequestContext, is actually an instance of Jersey specific ContainerRequest. If you look at the linked API, you will find a bufferEntity() method. This allows us to read the entity, and Jersey will be able to read it again. So your first step is to make that call
#Override
public void filter(ContainerRequestContext requestContext)
ContainerRequest cr = (ContainerRequest) requestContext;
cr.bufferEntity();
}
Now you can get the entity. If you look at the API for ContainerRequest, there are also methods to readEntity(..). If you are familiar with the JAX-RS Client API, you may have before used Response#readEntity(...class) to read the response entity. The ContainerRequest#readEntity(..) works pretty much the same way.
So if you know what the JSON format is supposed to be, and you have the POJO, you could do
POJO pojo = cr.readEntity(POJO.class);
Otherwise, if the format will change from request to request, you could extract the data as a map
Map<String, Object> json = cr.readEntity(new GenericType<Map<String, Object>>(){});
UPDATE
If you are using one JAX-RS APIs, and not Jersey specific APIs, then the above is not doable. You will instead need to read the stream to get the JSON, and set the stream back, so that Jersey can read it. If might look something like
InputStream entityIn = requestContext.getEntityStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// write `entityIn` to `baos`
byte[] bytes = baos.toByteArray();
POJO pojo = new ObjectMapper().readValue(bytes, POJO.class);
// do something with POJO
requestContext.setEntityStream(new ByteArrayInputStream(bytes));
Of course you will need to some JSON deserializer to do this. I just used Jackson in the example.
It's not as elegant as the first example, but you don't have much option if you are strictly sticking the JAX-RS APIs. If you can I would suggest just adding the Jersey dependencies to your project as provided (compile-time) so that you can use the APIs, since you are using Jersey with WebLogic anyway.

Jersey: Is there a clean way to specify allowed URL extensions?

I'm using Jersey 1.17.1 and on every URL I've created I want to allow people to put ".json" at the end or not. Here's an example of what I've done:
#GET
#Path("basepath{extension: (\\.json)?}")
public String foobar() {
...
}
Eventually I'm going to let them choose between nothing, ".json" or ".xml" and I'm concerned about my DRY violation here. I'll have to change every #Path to this instead:
#GET
#Path("basepath{extension: (\\.json|\\.xml)?}")
public String foobar() {
...
}
Is there a better way to do this that lets my path value be more reusable? Although I can't use Jersey 2.0, I'd be interested to know if it can solve this problem.
One way to do this is to subclass PackagesResourceConfig and inform Jersey which extensions should map to which media types. For instance:
public class ExampleResourceConfig extends PackagesResourceConfig {
#Override
public Map<String, MediaType> getMediaTypeMappings() {
Map<String, MediaType> map = new HashMap<>();
map.put("xml", MediaType.APPLICATION_XML_TYPE);
map.put("json", MediaType.APPLICATION_JSON_TYPE);
return map;
}
}
and then your actual REST service might look like:
#GET
#Path("basepath")
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response foobar() {
...
}
Jersey will select the appropriate media type based on the url extension. Note that Response is returned instead of String. I'm not sure how you're building your response and what your requirements are but Jersey can handle converting your Java beans into either XML or JSON (or even JSONP) without a problem.
In the REST API implementation , the resource representation can be either xml or json or etc. This is not a good way of restful implementation if you specify the types as the extensions of the URL. The correct way is to use HTTP ACCEPT header
like Accept: application/json or
Accept: application/xml
Refer : http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

Is there any way to configure spring mvc to assume a content-type?

I have a method to which I want to post some json data, that looks like this
#RequestMapping(value = "/m1", method = RequestMethod.POST)
public Object m1(#RequestBody Map<String, ?> body) {
// do something
}
This works great when I set the content-type header to application/json when I post, but fails with an error if I don't (it cannot deserialize the post body into the map because it doesn't know how)
What would I have to configure in spring to make it use application/json as a default when no header is specified?
The class that converts the JSON to your object is called an HttpMessageConverter. I assume you are using the default Jackson one that comes with Spring. You can write a custom MessageConverter, that will always return true in it's supports method with your response object type and then just call the Jackson httpconverter in your readInternal and writeInternal methods. If you do this however, be careful, as once it's registered in your requesthandler, it will be asked on all #ResponseBody and #RequestBody requests.

Categories

Resources