How do I map JSON parameters to Jersey parameters? - java

I've been struggling all day, trying to bind a very simple JSON request to a method using Jersey. I can't seem to find what's wrong, any help is very appreciated.
My JSON request is as simple as this:
{"user":"xyz","pwd":"123"}
My Jersey class looks like this:
#Path("/rest")
public class JerseyService {
#POST
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
#Consumes(MediaType.APPLICATION_JSON)
#Path("authenticate.svc")
#Transactional(readOnly = true)
public Response authenticate(
String user,
String pwd) throws IOException {
Response.ResponseBuilder responseBuilder = Response.ok();
responseBuilder.entity(JsonSerializer.serialize(Status.SUCCESS));
return responseBuilder.build();
}
}
When I send the JSON request to the service as it is, the "user" parameter is set with the entire JSON request as a String (user = "{\"user\":\"xyz\",\"pwd\":\"123\"}"), while pwd remains null.
I've tried using #QueryParam, #FormParam among another annotations with both "user" and "pwd", but I can't find a way for Jersey to bind the JSON values to the Java parameters.
Any ideas of what I'm doing wrong?
Thanks!

You could use low level JSONObject or create your own Class to accept the json parameter.
The following is the example with JSONObject.
```
#Path("/rest")
public class JerseyService {
#POST
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
#Consumes(MediaType.APPLICATION_JSON)
#Path("authenticate.svc")
#Transactional(readOnly = true)
public Response authenticate(final JSONObject login) throws IOException {
System.out.println(login.getString("user"));
System.out.println(login.getString("pwd"));
//^^^^^^^^^^^^^^^^^
Response.ResponseBuilder responseBuilder = Response.ok();
responseBuilder.entity(JsonSerializer.serialize(Status.SUCCESS));
return responseBuilder.build();
}
}
```

Related

Can I accept JSONObject as parameter in Rest API?

My code is as follows:
#Path("/test")
public class Test {
#POST
#Path("/postSomething")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public RestMessageResponse postSomething(JSONObject inputJSONObject) {
..do something
}
}
when I send a post request to the appropriate url, it doesn't reach the code.
Why would you want to do this anyway?
Just send the plain JSON in your HTTPRequest and parse it. For me, this usually looks like this:
#RequestMapping(path= "/app/syncImages", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
public ResponseEntity<?> someMethod(#RequestBody String body){
JSONObject request = new JSONObject(body);
...
}
Have you tried your code? Does it not work in some capacity?

Use #POST instead of #GET to get user input

I am a newbie to JSON. I wish to ask that how can I convert the following code from #GET to #POST so that I can retrieve the appdataid from user JSON input and not from the link.
AppDataService ads = new AppDataService();
#GET
#Path("/{appdataid}")
#Produces(MediaType.APPLICATION_JSON)
public AppData getAppData(#PathParam("appdataid")long appdataid){
return ads.getAppData(appdataid);
}
Code for AppDataService
public AppDataService(){
appdatas.put(1L, new AppData(1,"Success", " ", "123456"));
appdatas.put(2L, new AppData(2,"Failure", " ", "654321"));
}
public AppData getAppData(long id){
return appdatas.get(id);
}
Instead of user entering http://localhost:8080/gni/webapi/appdata/1 for the result
{
"id": 1,
"message": " ",
"status": "Success",
"token": "123456"
}
I hope that I can receive the user input with #POST and JSON format.
I have tried the following code but not working.
#POST
#Path("/{appdataid}")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public AppData getAppData(#PathParam("appdataid")long appdataid){
return ads.getAppData(appdataid);
}
Thanks for everyone that willing to help me.
If you want to POST JSON to your resource, you need to define a POJO for it to deserialise the message body into, for example:
public class AppDataRequest {
#JsonProperty
private long id;
public long getId() {
return id;
}
}
The use this type for in the resource:
#POST
#Path("/")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public AppData getAppData(AppDataRequest appDataRequest){
return ads.getAppData(appDataRequest.getId());
}
Note, the #Path annotation no longer has appdataid templated, and the parameter does not have an annotation.
SIDE NOTE
I have to wonder what you are trying to achieve here. The HTTP methods can and should be used to help describe the behaviour of your system. A request to get data should use a GET resource. POST resources should be used for creating new data. Sometimes there are good reasons to break this convention (such as the lack of a message body in a GET request), but there are usually other ways around them. Everything about your example tells my it should be a GET request, but I do not know the specifics of you application, so feel free to ignore this if it does not apply.
I don't think you really need JSON for that. You can use #FormParam for such a simple payload (ID)
#POST
#Path("some_url")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)//optional
public AppData getAppData(#FormParam("appdataid")long appdataid){
return ads.getAppData(appdataid);
}
You can call your web service from a console (Jersey assumed)
WebTarget target = client.target(UriBuilder.fromUri("http://localhost:8088/Your_root_url").build());
try{
MultivaluedMap<String, Integer> formData = new MultivaluedHashMap<String, String>();
formData.add("appdataid", 1);
Response res= target.path("some_url").request().
post(Entity.entity(formData, MediaType.APPLICATION_FORM_URLENCODED));
AppData entity = (AppData) res.readEntity(AppData.class);
//System.out.println(entity);//if toString() is overriden
}catch(Exception e){
System.out.println(e);
return;
}
EDIT: The only reason I see for wanting to use a POST in this situation is securiry (and even that is arguable)

Simple restful JSON POST with java as server and jquery as client

Before I ask my question I have to say that I have read more than 20 questions and articles about this problem and none of them could solve it.
My problem is I have a restful server in java like this:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(#RequestBody final String stringRequest, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
And I have tried different ways to send a json to this server with jquery (but all of them create errors):
$.ajax({
url:"/downloadByCode",
type:"POST",
data: JSON.stringify({"name":"value"}) });
415 "errors message" : "Content type 'application/x-www-form
urlencoded;charset=UTF-8' not supported", "type" :
"HttpMediaTypeNotSupportedError"
So I tried to fix it by adding contentType:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
400 "errors message" : "Could not instantiate JAXBContext for class
[class java.lang.String]: null; nested exception is
javax.xml.bind.JAXBException\n - with linked
exception:\n[java.lang.NullPointerException", "type"
:"HttpMessageConversionError"
I tried to send json object directly instead of JSON.stringify and it gives the same 400 error.
I tried to add different consumes to the #requestMapping but still no luck.
I tried to define my own class instead of JsonNode but it does not change anything.
Any ideas?
Please try to create new class :
public class InputData{
private String name;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
}
Then
public void downloadByCode(#RequestBody InputData stringRequest, final HttpServletResponse response)
And
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
try #RequestBody final Map<String, String> stringRequest
also you will need consumes = "application/json" on the #RequestMapping because you have that in your AJAX call
You will get 400 if spring doesn't like the format in which you send your ajax - I've had so much trouble with this in the past and it seems better to just ignore header types and content types unless necessary
You might try sending your response back as a ResponseEntity instead of using the HttpServletResponse directly. My hunch is that second argument, the HttpServletRequest argument, is what is causing the problem. I've never used that. I've always send my response back using the spring mvc api.
With Jersey api you can try just:
#POST
public void downloadByCode(String stringRequest)
and I think you'll find the body of your post in stringRequest.
You can take request body as string with usage of org.springframework.http.HttpEntity<String> as request type, here is example with your code as base:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(final HttpEntity<String> request, final HttpServletResponse response)
{
try
{
final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
But maybe it will be better to use also String as return type, if you are planning to return result as string value, like this:
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public String downloadByCode(HttpEntity<String> request) {
String requestBody = request.getBody();
String result;
// ...
// some processings here to create the result text
// ....
return result;
}
I made simple application using Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven and JDK >= 1.7.
#clonning repository with sample
git clone git#github.com:mind-blowing/samples.git
#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text
#running application using maven spring-boot plugin
mvn spring-boot:run
After application will be started you can open http://localhost:8080 and you will see html page with simple usage of JQuery to send POST requests, text of request and response will visible on html page, in controller I added two handlers, first with usage of HttpEntity and second with usage of POJO.
Controller: SampleRestController.java
HTML page: index.html
Project: https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text
First of all If you are using maven you should add dependency for jackson
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.1</version>
</dependency>
or you can download the jar and put it in our project class path (you can use other mapper as well)
then you should create a model or DTO class where you can map your json
public class Data{
private String name;
pubilc Data(){}
//getter and setter
}
THEN you controller
#RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public Data downloadByCode(#RequestBody final Data data, final HttpServletResponse response)
{
//your code
return data;
}
AJAX CALL
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
(Optional)You can override behavior by telling object mapper not to fail on missing properties by defining the bean as follows:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
return converter;
}
http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/
Looking at your errors, it's clear that you have configured 'Jaxb2RootElementHttpMessageConverter' or similar XML converter in your spring configuration. And since you have registerned an XML converter, the #RequestBody and #ResponseBody work based on the registered message converters.
So, to solve your problem, go with a JSON message converter such as 'MappingJacksonHttpMessageConverter'. Once you register a JSON message converter, create a bean class to hold your json data and use it with RequestBody as below:
// It has to meet the json structure you are mapping it with
public class YourInputData {
//properties with getters and setters
}
Update 1:
Since you have defined multiple message converters, Spring tries to use the first one available by default. In order to use specific message converter(in this case Jackson converter), you should specify 'Accept' header from client like below:
$.ajax({
headers: {
"Accept" : "application/json; charset=utf-8",
"Content-Type": "application/json; charset=utf-8"
}
data: "data",
success : function(response) {
...
} })
The final answer is a combination of a number of answers/comments in this question that I am going to summarize them here:
1- You have to make sure you have an appropriate json converter in your spring config such as MappingJacksonHttpMessageConverter (credits to #java Anto)
2- You have to create a POJO class with same structure as your json object (see #Vinh Vo answer)
3- Your POJO class cannot be an inline class unless it is a static class. It means it should have its own java file or it should be static. (credits to #NTyler)
4- Your POJO class can miss parts of your json object if you set it appropriately in your object mapper (see #Aman Tuladhar answer)
5- Your ajax call requires contentType:"application/json", and you should send your data with JSON.stringify
Here is the Final code that is working perfectly:
public static class InputData
{
private String name
public String getName()
{
return name;
}
public void setName(final String name
{
this.name = name;
}
}
#RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)
#ResponseBody
public void downloadByCode(#RequestBody final InputData request, final HttpServletResponse response)
{
try
{
String codes = request.getName();
// ...
// some processings here to create the result
// ....
final ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(result);
// Flush the result
outputStream.flush();
}
catch (final Exception exception)
{
LOG.debug("Exception Thrown [downloadByCode]", exception);
}
}
And it is the jquery Ajax request:
$.ajax({
url:"/downloadByCode",
contentType:"application/json",
type:"POST",
data: JSON.stringify({"name":"value"}) });
Delete the #ResponseBody on your downloadByCode method
Change your method downloadByCode() return type to String and then return the String
Response body will automatically convert the returned String to JSON and then use the data appropriately
I am not that well versed with java but as much as I know your java code must be something like this.
public class downloadByCode{
#GET
#Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public Response downloadByCode(#QueryParam("paramater1") final String parameter 1, #Context HttpServletRequest httpRequest) {
If this not helps you can keep you code somewhere and share it.

How to pass JSON String to Jersey Rest Web-Service with Post Request

I want to create a REST Jersey Web-Service accepting JSON string as input parameter.
Also I will use post requestand from webmethod I will return one JSON string.
How can I consume this in a HTML page using Ajax post request.
I want to know what all changes I need to make it on web method to accept JSON String.
public class Hello {
#POST
public String sayPlainTextHello() {
return "Hello Jersey";
}
}
Need to break down your requests. First, you want to accept a JSON string. So on your method you need
#Consumes(MediaType.APPLICATION_JSON)
Next, you need to decide what you want your method to obtain. You can obtain a JSON string, as you suggest, in which case your method would look like this:
#Consumes(MediaType.APPLICATION_JSON)
public String sayPlainTextHello(final String input) {
Or alternatively if your JSON string maps to a Java object you could take the object directly:
#Consumes(MediaType.APPLICATION_JSON)
public String sayPlainTextHello(final MyObject input) {
You state that you want to return a JSON string. So you need:
#Produces(MediaType.APPLICATION_JSON)
And then you need to actually return a JSON string:
return "{\"result\": \"Hello world\"}";
So your full method looks something like this:
#PATH("/hello")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public String sayPlainTextHello(final String input) {
return "{\"result\": \"Hello world\"}";
}
Regarding using AJAX to send and receive, it would look something like this:
var myData="{\"name\": \"John\"}";
var request = $.ajax({
url: "/hello",
type: "post",
data: myData
});
request.done(function (response, textStatus, jqXHR){
console.log("Response from server: " + response);
});
This will work. "path" is the relative URL path to be used in AJAX call.
public class Hello {
#POST
#Path("/path")
#Produces({ "text/html" })
public String sayPlainTextHello() {
return "Hello Jersey";
}
}

How to access JSON request body of POST/PUT Request in Apache Camel/CXF REST webservice

I am trying to pass a JSON request body to a REST Webservice which is made using CXFRS in my Apache Camel application.
I want to access the request JSON passed in my Processor.
REST URL:
http://localhost:8181/mywebservice/Hello/name/{request_param}
Though i am posting a JSON in request body, still in my processor exchange.getIn().getBody() always return the {request_param} not the Request JSON.
My REST webservice is as follows:
#Path("/name/")
#Consumes({"application/json" ,"application/xml"})
public class HelloRest {
#POST
#Path("/{name}")
public TestPojo sayHi(#PathParam("name") String name) {
return new TestPojo(name);
}
}
Server part:
#POST
#Path("/")
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.APPLICATION_JSON)
public String add(MappingUser newUser){
UserEntity userEntity = new UserEntity(newUser.getNickname(), newUser.getPassword());
boolean ret = myDB.addUser(userEntity);
//sends the return value (primitive type) as plain text over network
return String.valueOf(ret);
}
Client part:
public boolean addUser(User user){
WebResource resource = client.resource(url).path("/");
String response = resource
//type of response
.accept(MediaType.TEXT_PLAIN_TYPE)
//type of request
.type(MediaType.APPLICATION_JSON_TYPE)
//method
.post(String.class, user);
return Boolean.valueOf(response);
}

Categories

Resources