I am busy with a Dropwizard application and need to have an array injected to a POJO as one of the parameters of a put method. Unfortunately the array is not properly handled which results in a Bad Request response. To illustrate the JSON passed by the frontend looks like:
{
"name": "Jon",
"surname": "Doe",
"children": ["Chris", "Dave", "Sam"]
}
And my Java representation:
public class Person{
private String name;
private String surname;
private List<String> children;
public Person(){
}
#JsonProperty
public String getName(){
return name;
}
#JsonProperty
public void setName(String name){
this.name=name;
}
#JsonProperty
public String getSurname(){
return surname;
}
#JsonProperty
public void setsurname(String surname){
this.surname=surname;
}
#JsonProperty
public List<String> getChildren(){
return children;
}
#JsonProperty
public void setChildren(List<String> children){
this.children=children;
}
}
And in my resource class:
#PUT
#Timed
#UnitOfWork
#Path("/{userid}")
public Response getData(#PathParam("userid") LongParam userId,
Person person) {
// Do some stuff with the person
}
How can I properly handle the deserialization of the array in the JSON?
EDIT
I am using an angular front-end and I am invoking the method as follows:
function(json){
return $http({
url: API_URL.people+"/update/personID",
method: "PUT",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
data: json
});
}
Where the json argument contains the name, surname and children as above.
Looks like the GET service is defined incorrectly. It shouldn't have Person defined.
As per http method definition, the GET http method can't have body. So you can't have Person as the input parameter.
If you need to send Person to service, you may need to change the http method to POST or something else (like PUT) based on your requirement.
#GET
#Timed
#UnitOfWork
#Path("/{userid}")
public Response getData(#PathParam("userid") LongParam userId) {
// Do some stuff with the person
}
Turns out the code I provided words like a charm. Upon further investigation I made a mistake in the javascript object which got converted and sent as JSON which caused the error.
Related
Summary
I'm trying to define the generic type of params based on the Type property when the request arrives at the controller ?
If the Type is UPDATE, set the generic type of params to MovieParam, if the type CREATE, set it to CarParam.
Request Json
{
"values":[
{
"context":{
"type":"UPDATE",
"ids":[1,2,3,4,5],
"params":{
"code":1256,
"year":588987,
"name":"Suits Mike Harvey Specter",
"channel":"NetFlix"
}
}
},
{
context":{
"type":"CREATE",
"ids":[1,2,3,4,5],
"params":{
"brand": "Chevrolett",
"engine": 2.0,
"segments": "Autos",
"year": "2014",
"name": "Celta"
}
}
}
]
}
Mappings in Java with Spring
public class Request {
List<Value> values;
}
public class Value {
Context context;
}
public class Context<T> {
String type;
List<Long> ids;
T params;
}
public class MovieParam {
Long code;
Long year;
String name;
String channel;
}
public class CarParam {
String brand;
Long engine;
String segments;
String name;
Long year;
}
My Controller
#PostMapping
private ResponseEntity<?> publish(#RequestBody Request request) {}
When my controller receives the payload shown above, the params property is of type linkedhashmap because it doesn't know the type of that object. I would like to transform this type to the corresponding shown above.
I would like to think of something simpler and more direct, sometimes an interceptor, or some implementation of a strategy based on Type
I tried to validate the list of json request but it is not working.
Json request
[
{
"name": "AA",
"location": "Newyork"
},
{
"name": "BB",
"location": "Delhi"
}
]
Here is my controller class
Controller class
#RestController
#Validated
#RequestMapping("/v1.0")
public class Controller {
public ResponseEntity<List<Response>> ConversionResponse( #RequestBody List<#Valid Request> req) throws Throwable {
List<Response> response = new ArrayList<Response>();
for (request request : req) {
response = services.conversion(request, response);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
Here #Valid annotation doesnot validate the list
POJO class
public class Request{
#NotNull
private String name;
#NotNull(message="Location should not be null")
private String location;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
Please help me on this.
After Spring-boot 2.3.0, you need to manually add the
spring-boot-starter-validation to your project.
Use #RequestBody List<#Valid Req> reqs instead of #RequestBody #Valid List<Req> reqs.
Add #Validated on the Controller Class.
It will throw ConstraintViolationException, so you may want to map it into 400 Bad Request.
sources: Baeldung, Question 39348234
I have a Spring rest endpoint doing a simple hello app. It should accept a {"name":"something"} and return "Hello, something".
My controller is:
#RestController
public class GreetingController {
private static final String template = "Hello, %s!";
#RequestMapping(value="/greeting", method=RequestMethod.POST)
public String greeting(Person person) {
return String.format(template, person.getName());
}
}
Person:
public class Person {
private String name;
public Person() {
this.name = "World";
}
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
When I make a request to the service like
curl -X POST -d '{"name": "something"}' http://localhost:8081/testapp/greeting
I get
Hello, World!
Looks like it isn't deserializing the json into the Person object properly. It's using the default constructor and then not setting the name. I found this: How to create a POST request in REST to accept a JSON input? so I tried adding an #RequestBody on the controller but that causes some error about "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported". I see that is covered here: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for #RequestBody MultiValueMap which suggests removing the #RequestBody
I have tried removing the default constructor which it doesn't like either.
This question covers null values REST webservice using Spring MVC returning null while posting JSON but it suggests adding #RequestBody but that conflicts with above...
You must set the #RequestBody to tell to Spring what should be use to set your personparam.
public Greeting greeting(#RequestBody Person person) {
return new Greeting(counter.incrementAndGet(), String.format(template, person.getName()));
}
You must set 'produces' with #RequestMapping(value="/greeting", method=RequestMethod.POST)
use below code
#RequestMapping(value="/greeting", method=RequestMethod.POST, produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public String greeting(#RequestBody Person person) {
return String.format(template, person.getName());
}
How can I parse this response without having to create a separate response class for each entity.
{
"data": {
"id": 100,
"first_name": "Michael",
"last_name": "Blankenship"
}
}
I would like to have a generic class that can reference the data object and then just specify what type of class that should be used to parse the response
Something like this:
#Get
Call<User> getUser();
#Get
Call<Status> getStatus();
Without having to have multiple response classes for each type
public class UserResponse {
User data;
}
public class User {
String first_name;
String last_name;
}
public class StatusResponse {
Status data;
}
Workaround for this would create a generic class something like this
public class BaseResponseWrapper <T> {
#SerializedName("data")
private T data;
public BaseResponseWrapper(){
super();
}
public T getData() {
return data;
}
}
I have a JSON Object
{
"firstname": "foo",
"account":
{
"city": "bar"
}
}
which I want serialize in a REST backend:
#POST
public Response create(Employee e)
Classes:
public class Employee {
public String firstname;
private Address address;
}
public class Address {
public String city;
}
Unforutanetly, I always receive a 400 status code. But if I do
public Response create(Object o)
everything works fine. Any ideas?
Your JSON does not correspond (map) to your POJO types. In the JSON, you have account, but in your Java type you have address.