I'm trying to create a POST servlet that should be called with JSON request. The following should work, but does not. What might be missing?
#RestController
public class MyServlet {
#PostMapping("/")
public String test(#RequestParam String name, #RequestParam String[] params) {
return "name was: " + name;
}
}
JSON POST:
{
"name": "test",
"params": [
"first", "snd"
]
}
Result: name is always null. Why?
"Response could not be created: org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'name' is not present"
In general I don't pass a request param in a POST method. Instead, I am using a DTO to pass it in the body like:
#RequestMapping(value = "/items", method = RequestMethod.POST)
public void addItem(#RequestBody ItemDTO itemDTO)
Then, you need to create the ItemDTO as a POJO with the necessary fields.
In addition to #stzoannos answer, if you do not want to create POJO for json object, you can use google GSON library to parse json into JsonObject class, which allow to work with parameters through same as get and set methods.
JsonObject jsonObj = new JsonParser().parse(json).getAsJsonObject();
return "name is: " + jsonObj.get("name").getAsString();
Related
I know this is very basic, but I have a problem with deserializing json using jackson when the format is like this :
I created a class Person with id, name and place and tried to read the results from API call using jackson (using the #JsonProperty annotation), but when I debug the persons variable is null:
json body:
{ people:[
{
"id":"0",
"name":"Bob",
"place":"Colorado",
},
{
"id":"1",
"name":"John",
"place":"Chicago",
},
{
"id":"2",
"name":"Marry",
"place":"Miami",
}
]}
RequestEntity<Void> reqEntity = RequestEntity.get(new URI(url))
.accept(MediaType.APPLICATION_JSON)
.build();
ResponseEntity<List<Person>> persons = template.exchange(reqEntity, new ParameterizedTypeReference<List<Person>>() {});
You should wrap your List<Person> in another Response object, which has a people field, containing your list:
public class PeopleResponse {
private List<Person> people;
// getter and setter
}
Then you can change your ResponseEntity according to that:
ResponseEntity<PeopleResponse> response = template.exchange(reqEntity, new ParameterizedTypeReference<PeopleResponse>() {});
List<Person> people = response.getBody().getPeople();
I have created one rest API in spring-boot, the problem is that I am taking 4 parameters as a requestbody argument as a JSON object.
Now if I pass the JSON object with 5 parameters than my API still call, no assertion exception occurs while serializing the JSON object.
I have one dto class as below with constructor
public class testDto{
#NotNull(message = "fistName can not be null.")
private String fistName;
#NotNull(message = "lastName can not be null.")
private String lastName;
private String nickName;
public testDto() {
}
public testDto(#NotNull(message = "fistName can not be null.") final String fistName ,#NotNull(message = "lastName can not be null.") final String lastName , final String nickName){
super();
this.fistName = fistName;
this.lastName = lastName;
this.nickName = nickName;
}
}
My restapi as below,
#PostMapping(path ={ "/api/v1/user"}, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> saveUser(
#Valid #RequestBody(required = true) final testDto dto) throws Exception {
}
Now while calling my API I am passing request body as below
{
"fistName" : "abc",
"lastName" : "xyz",
"nickName" : "pqr",
"age" : 25
}
Now here when I pass age parameter and call the API, my API still working instead of throwing an exception for No any constructor found as I have passed age which is not a member of my dto class.
Expected result: don't allow to call API
Actual result: Allow me to call API
I have also tried with assertion exception declaration and binding exception but not getting any success.
also set the property
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Spring Boot uses Jackson to map the JSON payload to an instance of your testDto class. By default, Jackson is configured to ignore entries in the JSON that it cannot map to the DTO. This follows the robustness principle or Postel's law as it's also known.
You can configure Jackson to fail when it cannot map an entry in the JSON to a property on a DTO by adding the following line to your application's application.properties file in src/main/resources:
spring.jackson.deserialization.fail-on-unknown-properties=true
What to do when the request is invalid json but the values are correct ex:
{
"fistName" : "abc",
"lastName" : "xyz",
"nickName" : "pqr",
"nickName" : "pqrs"
}
Now in this case it is taking the last one and mapping it
I have the following JSON that will be passed as part of a HTTP request, in the message body.
{
"names": [
{
"id":"<number>",
"name":"<string>",
"type":"<string>",
}
]
}
My current REST handler is below. I am able to get the Id and `Version that is passed in as path params, but I am not sure how to retrieve the contents on the message body?
#PUT
#Path("/Id/{Id}/version/{version}/addPerson")
public Response addPerson(#PathParam("Id") String Id,
#PathParam("version") String version) {
if (isNull(Id) || isEmpty(version)) {
return ResponseBuilder.badRequest().build();
}
//HOW TO RECIEVE MESSAGE BODY?
//carry out PUT request and return DTO: code not shown to keep example simple
if (dto.isSuccess()) {
return Response.ok().build();
} else {
return Response.serverError().build();
}
}
Note: I am using the JAX-RS framework.
You just need to map your name json to a POJO and add #Consumes annotation to your put method, here is an example:
#PUT
#Consumes("application/json")
#Path("/Id/{Id}/version/{version}/addPerson")
public Response addPerson(#PathParam("Id") String Id,
#PathParam("version") String version,
List<NamObj> names) {
I assume you are trying to retrieve a list of elements if is not the case just use you POJO as it in the param.
Depending on what json library are you using in your server you may need to add #xml annotation to your POJO so the parser could know how to map the request, this is how the mapping for the example json should look like:
#XmlRootElement
public class NameObj {
#XmlElement public int id;
#XmlElement public String name;
#XmlElement public String type;
}
Jersey doc: https://jersey.java.net/documentation/latest/user-guide.html#json
#cosumes reference: http://docs.oracle.com/javaee/6/tutorial/doc/gilik.html#gipyt
With the below GET request:
ResponseEntity<String> entity = restTemplate.exchange(uri, HttpMethod.GET, requestEntity, String.class );
entity.getBody();
returns a JSON String like this:
{"userRegistrations":[{"userRegistrationToken":"fb398972","userRegistrationTokenAlias":"87f15f8"}]}
But I want to make this work with an object not with a string. So with the code below I receive a UserRegistrations object with a null UserTokenResponse List
ResponseEntity<UserRegistrations> entity = restTemplate.exchange(uri, HttpMethod.GET, requestEntity, UserRegistrations.class );
entity.getBody();
And my domain class looks like this:
public class UserRegistrations {
List<UserTokenResponse> userRegistrationList;
//..getters and setters
}
public class UserTokenResponse {
private String userRegistrationToken;
private String userRegistrationTokenAlias;
//getters and setters
}
What am I missing?
Assuming you're using Jackson, RestTemplate automatically registers a MappingJackson2HttpMessageConverter which configures the underlying ObjectMapper to ignore unknown properties.
The JSON object has a single attribute named userRegistrations, whereas your Java class has a single attribute named userRegistrationList. They don't match.
They need to match, or you need to add a #JsonProperty annotation of the attribute to make Jackson serialize/parse it as userRegistrations.
This happens when your class property names doesn't match with the JSON property names coming in the response. For instance take the below example
public class ScheduledCallbacks {
private List<Callback> callbacks;
public List<Callback> getCallbacks() {
return callbacks;
}
public void setCallbacks(List<Callback> callbacks) {
this.callbacks = callbacks;
}
#Override
public String toString() {
return "ScheduledCallbacks [callbacks=" + callbacks + "]";
}
}
and if the response is the following way
{
"scheduledCallbacks": [
{
"sessionId": "string",
"customerNbr": "string",
"topicName": "string",
"desiredTime": "string",
"callbackState": "string",
"serviceName": "string",
"expirationTime": "string",
"programCode": "string"
}
]
}
Then you get null response because the name scheduledCallbacks in the JSON response doesn't match with the name callbacks in class.
But if your class is as following
public class ScheduledCallbacks {
private List<Callback> scheduledCallbacks;
public List<Callback> getScheduledCallbacks() {
return scheduledCallbacks;
}
public void setScheduledCallbacks(List<Callback> scheduledCallbacks) {
this.scheduledCallbacks = scheduledCallbacks;
}
#Override
public String toString() {
return "ScheduledCallbacks [scheduledCallbacks=" + scheduledCallbacks + "]";
}
}
Then you get the expected response in response entity
I encountered a similar error and it was returning null too. The problem is over when Object.class is replaced with the name of the class we want to convert on the client side.
Like that:
Token = restTemplate.exchange(uri, HttpMethod.POST, request, Object.class);
the problem was probably due to the fact that it is not directly compatible with the class we want to convert.
I have been through this link. but this did not helped me out.
I am using jersey lib v1.17.1.
My jersey rest service:
#POST
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
#Path("/post1")
public ResponseBean post1(#QueryParam("param1")String param1)
{
return ResponseFactory.createResponse(param1, "TEST", "TEST", null, true);
}
url is: /test/post1
My ajax call:
var d = {"param1":"just a dummy data"};
$.ajax({
type : "POST",
url : "http://localhost:7070/scl/rs/test/post1",
contentType :"application/json; charSet=UTF-8",
data : d,
dataType : "json"
})
.done(function(data){
console.log(data);
})
.fail(function(data){
console.log(data);
});
It hits to my rest service but as param1 I am alway getting null value. The alternate solution is to add JavaBean with #XMLRootElement which will marshal/unmarshal the java object to json and vice versa, but I do not want to use this.
Is there any way to post data and receive it using appropriate annotation like #QueryParam or something like that ?
Please help
Your server-side code should be like this:
#POST
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
#Path("/post1")
public ResponseBean post1(Data param1)
{
return ResponseFactory.createResponse(param1, "TEST", "TEST", null, true);
}
where Data is a (POJO) class annotated with #XmlRootElement and corresponds to the JSON data what your client will send (ie, have a param1 field with getter and setter). The JAX-RS implementation will unmarshall the body of the POST into an instance of Data.
#QueryParam annotation is used ot retrieve the query params in a (usually) GET requests. Query params are the params after the question mark (?). Eg: #QueryParam("start") String start will map be set to 1 when the following request is processed: GET http://foo.com/bar?start=1, but this is not what you're doing in your case, AFAICS.
You can simply take Post dat as a string and then you can parse it using JSONObject.
#POST
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
#Path("/post1")
public Response postStrMsg(String msg) {
String output = "POST:Jersey say : " + msg;
return Response.status(200).entity(output).build();
}
the #XMLRootElement is the way to do that since the json must be unmarshaled before you can use any of its elements.