How to send model attribute to spring controller using Postman - spring

I want to test my controller using postman but don't know how to send a model attribute using postman.
I tried to send all attributes in row json fornamt and x-www-form-urlencoded in body but it is not working for me, I didn't understand where i'm getting wrong
My controller class looks like :
#RestController
public class DemoController {
#Autowired
private DemoService demoService;
#RequestMapping(value = "/userDetail", method = { RequestMethod.GET }, produces = { MediaType.APPLICATION_JSON })
public String testme(
ModelMap model,
#ModelAttribute("inputParameter") InputParameter inputParameter,
BindingResult result) {
return demoService.getDetail(inputParameter);
}
}
Model Class :
public class InputParameter {
private String id;
private String name;
private String number;
private String address;
private String pass;
}

Related

GET method: How to convert snake_case query string to camelCase DTO

I use snake_case DB columns and camelCase DTO.
And our team want to use snake_case when we code React component.
Because of it, I added #JsonNaming on DTO. But it works when I send Json data, as you know.
Is there any annotation or setting similar to #JsonNaming?
Here is my postman data and sample codes.
Debug data: sampleName=name, sampleDesc=null.
// Controller
#RestController
#RequestMapping("/sample")
public class SampleController {
#Autowired
private SampleService sampleService;
#GetMapping
public Result getSampleList(SampleDTO param) throws Exception {
return sampleService.getFolderList(param);
}
#PostMapping
public Result insertSample(#RequestBody SampleDTO param) throws Exception {
// this method works well with #JsonNaming
return sampleService.insertFolder(param);
}
}
// DTO
#Setter
#Getter
#NoArgsConstructor
#JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
#Alias("SampleDTO")
public class SampleDTO {
#NotNull
private Long sampleNo;
#NotBlank
private String sampleName;
private String sampleDesc;
#Builder
public SampleDTO(Long sampleNo, String sampleName, String sampleDesc) {
this.sampleNo = sampleNo;
this.sampleName = sampleName;
this.sampleDesc = sampleDesc;
}
}
I had the same problem and didn't find an annotation for this but maybe you can use #ConstructorProperties like this in your DTO's constructor:
#ConstructorProperties({"sample_no","sample_name","sample_desc"})
public SampleDTO(Long sampleNo, String sampleName, String sampleDesc) {
this.sampleNo = sampleNo;
this.sampleName = sampleName;
this.sampleDesc = sampleDesc;
}

Should the shared variable inside the service that is in the mvc controller be volatile?

Inside the MVC controller , I have a service that I access to get data:
#Controller
#AllArgsConstructor
public class DataController {
private SharedDataService sharedDataHolder;
#RequestMapping(value = "/testPoint", method = GET)
public String getData(#PathVariable String point, Model model){
Data data = sharedDataHolder.getData();
...
}
}
and SharedDataService :
#Service
public class SharedDataService {
private Data data;
public Data getData(){
if(isHourAgo()){
this.refreshData();
}
return data;
...
}
}
And actually the question is, should I make the data variable of the SharedDataService class volatile so that there is no conflict inside the controller?
Data :
public class Data {
private String title;
private Map<String,Double> characteristics;
}

Springboot restinvokation with an non existing field

Suppose I have a model UserInfo which I used in my post service as #RequestBody and when I invoke the service with UserInfo payload it is working.
Class UserInfo {
Private String firstName;
Private String lastName
}
How do I restrict the post call if someone sends some additional fields in the payload which is not exists in UserInfo model (e.g. age)?
In this case, are you using this?
#Autowired
ServiceInterface serviceInterface;
#PostMapping(value = "/userSave")
#RequestBody
public RequestEntity saveUserInfo(**#ModelAttribute** UserInfo userInfo){
return new ResponseEntity(serviceInterface.saveUser(userInfo),HttpStatus.OK);
}
when we are using #ModelAttribute annotation this gets only attribute values in UeserInfo DTO (DATA TRANSFER OBJECT). Also, you can use validations in the UserInfo DTO Class. Like
Class UserInfo {
#NotNull
private String firstName;
#NotNull
private String lastName;
}
But However when using #RequestBody whatever user sends additional data that save only UserInfo Attribute data.
Try to add a property to application.properties:
spring.jackson.deserialization.fail-on-unknown-properties=true
Or create a component:
#Component
public class Jackson2ObjectMapperBuilderCustomizerImpl implements Jackson2ObjectMapperBuilderCustomizer {
#Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.featuresToEnable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}
}

How to send Java collections containing subclasses to spring controller

I'm trying to send collections to my spring MVC controller:
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#ModelAttribute("mapperList") MapperList mapperList) {
//prints {"users":null}
System.out.println(new ObjectMapper().writeValueAsString(mapperList));
return new ResponseDTO();
}
this is the code posting my users :
public ResponseDTO postUsers(ArrayList<User> users) {
ResponseDTO serverResponse = null;
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setRequestMethod("POST");
// prints {"users":[{"property1":"x","property1":y}]}
System.out.println(objectMapper.writeValueAsString(new MapperList(users)));
objectMapper.writeValue(connection.getOutputStream(), objectMapper.writeValueAsString(new MapperList(users)));
//blabla ...
}
and this is the object containing my list :
public class MapperList implements Serializable {
private static final long serialVersionUID = 8561295813487706798L;
private ArrayList<User> users;
public MapperList() {}
public MapperList(ArrayList<User> users) {
this.setUsers(users);
}
public ArrayList<User> getUsers() {
return users;
}
public void setUsers(ArrayList<User> users) {
this.users = users;
}
}
and this is the users type to post:
public abstract class User implements Serializable {
private static final long serialVersionUID = -1811485256250922102L;
private String property1;
private String property2;
public User() {}
public User(String prop1, String prop2) {
// set properties
}
// getters and setters
}
the problem is, when I output the value of the users's array before to post it to the controller, I got the following json value :
{"users":[{"property1":"x","property1":y}]}
but in the controller, when I print what I get from the request body, I only get :
{"users":null}
I also tryed with the annotation #RequestBody instead of #ModelAttribute("mapperList") and a JSONException is displayed :
*A JSONObject text must begin with '{' at 1 [character 2 line 1]\r\n*
My array list of users contains only one user that should be displayed. I don't understand why this doesn't work...
Thanks for any help !
You can chnage your MapperList class definition as public class MapperList extends ArrayList<User>{ ..} you dont need to define any instance variable like private ArrayList users inside MapperList class. Use #Requestbody annotation. You will be able to use MapperList as a ArrayList
Try to use:
public class MapperList{
private List<User> users;
//setter and getter
//toString
}
public class User{
private String property1;
private String property2;
//getter + setter
}
json:
{"users":[{"property1":"x", "property2":"y"}]}
in controller use #RequestBody. In that case Jackson will map your json to ArrayList of users.
#ResponseStatus(HttpStatus.OK)
#RequestMapping("/postUsers.do")
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList users) {
System.out.println(users);
return null;
}
no need to get objectMapper in that case. Don't forget to set content-type in request header to application/json. It required by Spring to handle #RequestBody processing.
If not working try to change MapperList:
List<User> users = new ArrayList<User>();
On the server side keep the #RequestBody annotation:
public #ResponseBody ResponseDTO postUsers(#RequestBody MapperList mapperList)
...
But this line causes problems:
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
First it converts the object to JSON and then again uses objectMapper to JSON-encode the string into output stream. Try the following instead:
connection.getOutputStream().write(
objectMapper.writeValueAsString(new MapperList(users))
.getBytes("UTF-8")
);
or directly output to stream:
objectMapper.writeValue(
connection.getOutputStream(),
new MapperList(users))
);
Zbynek gave me part of the answer. Indeed
objectMapper.writeValue(
connection.getOutputStream(),
objectMapper.writeValueAsString(new MapperList(users))
);
doesn't work properly in my case
But moreover, my User class was an abstract class, with many type of User as subclasses. so the #RequestBody annotation couldn't work without specified the object type in the Json.
I used the following annotations on User class to make it working :
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = SubClassA.class, name = "a"),
#JsonSubTypes.Type(value = SubClassB.class, name = "b")
})
Thanks a lot for all your answers.

JAXB Error while using in SpringREST to return a ArrayList of a domain object

I am trying to use JAXB in Spring RESTful webservice.
My code is as follows:
#RequestMapping(value = "/countries",
method = RequestMethod.GET,
headers="Accept=application/xml, application/json")
public #ResponseBody CountryList getCountry() {
logger.debug("Provider has received request to get all persons");
// Call service here
CountryList result = new CountryList();
result.setData(countryService.getAll());
return result;
}
The CountryList.java class looks like:
#XmlRootElement(name="countries")
public class CountryList {
#XmlElement(required = true)
public List<Country> data;
#XmlElement(required = false)
public List<Country> getData() {
return data;
}
public void setData(List<Country> data) {
this.data = data;
}
}
The Country.java looks like:
#XmlRootElement(name="country")
public class Country {
private Calendar createdDt;
private String updatedBy;
private String createdBy;
private Long id;
private String countryName;
private Calendar updatedDt;
// getters and setters for all attributes goes here
}
Now, when I access the method getCountry(), I am getting the following exception
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "data"
this problem is related to the following location:
at public java.util.List com.cisco.bic.services.model.CountryList.getData()
at com.cisco.bic.services.model.CountryList
this problem is related to the following location:
at public java.util.List com.cisco.bic.services.model.CountryList.data
at com.cisco.bic.services.model.CountryList
Would anyone has any idea why is this error coming. Am I doing anything wrong in the annotaion part ??
Please help.
Regards
Saroj
You can't annotate both the getter/setter and the field, you need to decide on one of them.

Resources