RestAssured, POJO and dealing with lists - pojo

I'm writing a test for an API and at one endpoint I get JOSN in response with couple arrays into one array.
Can I make POJO class which mapping those array/arrays into a class object?
for example, JSON in response looks like this:
{
"total": 55,
"limit": 500,
"skip": 0,
"data": [
{
"id": 13,
"email": "probe#gmail.com",
"phone": "121-121-123",
"firstName": "Prob",
"lastName": "Buraz",
"platforms": [
{
"id": 3,
"name": "Dowe Assis",
"url": "ins.probe.com",
"user_platforms": {
"id": 496,
"userId": 13,
"platformId": 100,
"user_id": 82
}
}
], .....
And so on. I suppose that I can use this class for mapping response into POJO:
#JsonIgnoreProperties(ignoreUnknown = true)
public class GetUsers {
public Integer total;
public Integer limit;
public List<DataReference> data;
#JsonIgnoreProperties(ignoreUnknown = true)
public static class DataReference{
public int id;
public String email;
public String phone;
public String firstName;
public String lastName;
public List<Platform> platforms;
#JsonIgnoreProperties(ignoreUnknown = true)
public static class Platform{
public Integer id;
public String name;
public String url;
}
}
}
But in the test code i can get nothing more then data elements. platforms elements are untouchable:
GetUsers users = given()
.header("Authorization",
"Bearer " + adminToken) //
.when()
.get()
.then()//.log().all()
.statusCode(200)//.log().all()
.extract().as(GetUsers.class);
i can checks values of array data like those:
assertThat(users.data).extracting(user -> user.email).contains("probe1#gmail.com", probe+2#gmail.com, ... );
But i can't access to any value of users.data.platforms.name or users.data.platforms.id and so on.
How I can access to platform element for one of users?
users.data.platforms.name
How i can do that (access platforms data) for one or for all listed users in data array?

Which library you are using for JSON POJO mapping?
If there is no error with mapping then platform variable can be accessed using following.
Add getter setter in POJO
users.getData.getindex(0).getplatforms.getindex(0).getid();
users is object of GetUsers Class which is used to map the JSON response.

Related

how to save parent object containing child object using spring boot in #ManyToOne unidirectional mapping?

I am new in spring boot. I've two model classes Party(parent) and PartyCategory(child). PartyCategory stores data id, labelAr and labelEn successfully.
Now I am passing child id in json request and getting null values for labelAr and labelEn in json response as pasted below. Can someone please help what and doing wrong here.
I've pasted my code as well.
Json Request:
{
"name": "Party A",
"description": "Description of Party A",
"category": {
"id": 1
}
}
Json response;
{
"id": 6,
"name": "Party A",
"description": "Description of Party A",
"category": {
"id": 1,
"labelAr": null,
"labelEn": null
}
}
Party.java:
public class Party {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String description;
#ManyToOne(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
#JoinColumn(name = "category_id")
private PartyCategory category;
....setters and getters
}
PartyCategory.java:-
public class PartyCategory {
#Id
#GeneratedValue
private Integer id;
private String labelAr;
private String labelEn;
...setters and getters..
Repositories:
public interface PartyCategoryRepository extends JpaRepository<PartyCategory, Integer> {
}
public interface PartyRepository extends JpaRepository<Party, Integer> {
}
Services:
public class PartyServiceImpl {
#Autowired
PartyRepository partyRepository;
public Party saveParty(Party party) {
return partyRepository.save(party);
}
Controller:
#RestController
public class PartyController {
#Autowired
PartyServiceImpl partyServiceIml;
#PostMapping(value = "/party/save")
public Party saveParty(#RequestBody Party party ) {
Party returnedParty = partyServiceIml.saveParty(party);
return returnedParty;
}
}
The problem is that the category you are posting is not recognised as being an existing category.
You can then do something like the below. Firstly, Create a Jackson converter class to customise the Json deserialisation. I was not sure if these were Spring managed but they are so you can then inject the necessary repository.
import com.fasterxml.jackson.databind.util.StdConverter;
#Component
public class CategoryConverter extends StdConverter<Integer, PartyCategory> {
#Autowired
private PartyCategoryRepository repo;
#Override
public PartyCategory convert(Integer value) {
return repo.findById(value).get();
}
}
Then update your entity as follows so that the category Json property will be handled via the converter created above. Note that in reality I would use a Jackson mix-in to apply this custom deserializer as this would avoid 'polluting' the entity class with Json processing instructions. You can look up how to do that.
#Entity
public class Party {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String description;
#ManyToOne
#JoinColumn(name = "category_id")
#JsonDeserialize(converter = CategoryConverter.class) //in real life use a 'mix-in'
private PartyCategory category;
}
Then you can post JSON as below where we simply specify the id of an existing category:
{
"name": "Party A",
"description": "Description of Party A",
"category": 1
}
By enhancing this solution to use mix-ins as suggested then it is possible then to cleanly separate the view model from the entity model without having to create a DTO layer which will typically largely duplicate the entity model and which will required tedious mapping code to handle the conversions.
First of all, it's not a good practice to use the same entity for the database and also for the rest services. They should be separate entities, normally the entities for the rest services are called DTO (Data Access Objects).
Now, regarding your problem, it's normal what it's happening in your code, because you overwrite the PartyCategory labelAr and labelEn associated to the ID 1 with null values when you save your new Party, because you didn't provide any value for those two labels.
return partyRepository.save(party);
If you want to avoid this problem you have to retrieve the PartyCategory data first from the database, set to the Party entity and after that to save it to the database. Something like this:
public class PartyServiceImpl {
#Autowired
PartyRepository partyRepository;
#Autowired
PartyCategoryRepository partyCategoryRepository;
public Party saveParty(Party party) {
PartyCategory partyCategory = partyCategoryRepository.findById(party.getPartyCategory().getId());
party.setPartyCategory(partyCategory);
return partyRepository.save(party);
}

REST Api Spring boot with mongodb how to get json?

#GetMapping("/getAccount")
public Account validateAccount(#RequestBody) {
}
Very new to spring boot. My account file has 5+ values all strings, username, password, id, and some etc things.
Given this
{
"username": "bob"
"password": "password"
}
It should give this with 200 response code OK
{
"id": "45645646546"
"username": "bob"
"password": "password"
"status": "Single"
"filler": "filler"
}
However I'm not sure how to read the "username" and "password" json in my validateAccount function
Not really related to this question but does anyone know how to send a response code in the function? Like .sendresponseheader(400) something like that
public class AccountDTO {
#JsonIgnore
private Long id;
#NotNull
private String username;
#NotNull
private String password;
#JsonIgnore
private String status;
#JsonIgnore
private String filler;
// getters & setters
}
You may want to create a DTO (Data Transaction Object) as shown above. Here's a link to it's wiki.
Next pass map user input into this DTO using #RequestBody annotation.
#RestController
public class AccountController {
#GetMapping("/accounts")
public ResponseEntity<Account> validateAccount(#RequestBody AccountDTO accountDTO) {
return new ResponseEntity<>(accountService.validate(accountDTO), HttpStatus.OK);
}
}
Or you can use
#RestController
public class AccountController {
#GetMapping("/accounts")
public Response validateAccount(#RequestBody AccountDTO accountDTO) {
return new ResponseEntity().ok(accountService.validate(accountDTO));
}
}
The user input will be converted from json to AccountDTO using whatever JSON processor your're using most probably it'll be com.fasterxml.jackson.core.
The #JsonIgnore and #NotNull annotation will ensure only username and password fields are used and others are ignored while taking input from user.
You can pass this DTO to your service classes and use something like findByUsername() in your Business Logic and return populated AccountDTO using the below mapper function or some external libraries like Model Mapper or MapStruct.
public toAccountDTO(Account account) {
AccountDTO accountDTO = new AccountDTO();
accountDTO.setUsername(account.getUsername());
// and so on...
return accountDTO;
}
And for your last query, wrap the returned AccountDTO object in ResponseEntity wrapper to provide a proper Response Code with your payload. Here's a link to ResponseEntity Java docs.
AccountDto.java
===============
class AccountDto{
private Long id;
private String username;
private String password;
private String status;
private String filler;
//getters & setters
}
#GetMapping("/getAccount")
public ResponseEntity validateAccount(#RequestBody AccountDto accountDto) {
return new ResponseEntity<>(accountServie.validate(accountDto),HttpStatus.OK);
}
You can do your custom operations before returning the response. Take a look Best Practice of REST
For json response nothing specific just mark class with #RestController.
For #RequestBody just use a pojo to bind the values
For error code and status you can use ResponseEntity

PagingAndSortingRepository not working when searching by Id of LIST of nested class

I am using PagingAndSortingRepository on Mongodb.
My model class is as follows:
public class Question {
#Id
private String id;
private List<Answer> answers;
//Other attributes
}
public class Answer {
#Id
private String id;
//Other attributes
}
My Repository is as follows:
public interface QuestionRepository extends PagingAndSortingRepository<Question, String> {
public List<Question> findByAnswersIdIn(List<String> answerIds);
}
For some reason, the result is empty records, even though they do exist.
Is the syntax different when dealing with List of nested class?
Sample Document:
{
"id": "58609cd88ba6bc24589a7850",
"mainQuestion": "Does this camera have built in wifi for photos transfer?",
"answers": [
{
"id": "586153458ba6bc22f8b7c4a1",
"mainAnswer": "Yes, it has wifi.",
"author": {
"id": "586153468ba6bc22f8b7c4a2",
"appUserId": "5851e7768ba6bc0dc0f288a6",
},
"verifiedAnswer": false
},
{
"id": "58616aed8ba6bc0c0c111d31",
"mainAnswer": "Yes, they do have wifi",
"author": {
"id": "58616aee8ba6bc0c0c111d32",
"appUserId": "5851e7768ba6bc0dc0f288a6",
},
"verifiedAnswer": false
}
],
"topic": "Nikon d5500",
"tags": null
}
It looks like the spring mongo db doesn't support the id annotation for embedded document.For your case if you can rename your id to answerId in the embedded document.
Update your Answer to something like below.
public class Answer {
private String answerId;
private String mainAnswer;
}
You can do something like this to save the questions with answers.
Question question = new Question();
List<Answer> answers = new ArrayList<Answer>();
Answer answer = new Answer();
answer.setAnswerId(new ObjectId().toString());
answer.setMainAnswer("Yes, it has wifi.");
answers.add(answer);
question.setAnswers(answers);
questionRepository.save(question);
And now you can do something like this to query the questions with answer ids.
List<Question> question =
questionRepository.findByAnswersAnswerIdIn(Arrays.asList("586153458ba6bc22f8b7c4a1"));
In my opinion your method should look like this :
public List<Question> findByAnswersIn(List<Answer> answers);
You give Strings not Answers. May be this is the problem.

How can i make sure that passing parameters don't have any cross site scripting contents

I am creating Rest Web services Using Spring & passing parameters to the method from model class.
My inputs parameters are as
{
"user_id": 23,
"user_email_id": "q#q.c",
"user_password": "fdsdsdf",
"firstname": "<script>window.alert(‘surprise!’);</script>",
"lastname": "kdfgkdf",
"mobile_number": "1414141414",
"user_status": 1,
"isdeleted": 0,
"created_by": 1,
"profile_picturename": "kfksdjfhksjd",
"address": "sfdsdfsd"
}
& My ReST controller method is as
#RequestMapping(value = "/validate", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Object AddUser(#Valid #RequestBody UserInputModel userInputModel, BindingResult br, HttpServletResponse response) throws Exception {
//Logic
}
Here i want to make sure that passing parameter dont contain any Xss or how can i make sure that HTML encoder will work for my input model
Thanks in advance
Use Hibernate Validator's #SafeHtml annotation:
https://docs.jboss.org/hibernate/validator/5.2/reference/en-US/html/ch02.html#validator-defineconstraints-hv-constraints
You need to add jsoup as a dependency
Example:
#Entity
public class Foo {
#SafeHtml(...)
private String firstName;
}
Then if you validate the entity, it will be not valid if firstName contains xss

REST Service - JSON mapping for dynamic parameters

Let us take the following JSON response which I want to return from my REST service,
{
"id" : 123,
"name" : "ABC",
}
For the above JSON response, I can create a POJO class like,
public class Student{
private long id;
private String name;
//getters and setters
}
So, I can write a GET service to return the Student object which will be then transformed as JSON.
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response get(){
Student student = new Student();
student.setId(123);
student.setName("ABC");
return Response.ok(student).build();
}
It works fine. Now I want to introduce optional parameters to my JSON response as follows,
{
"id" : 123,
"name" : "ABC",
"params" : {"param1":"xxx","param2":342}
}
Here the params in the JSON response is an Object type and the attributes of that object are not fixed. It will vary for every request like sometime it can have 3 attributes and sometime it will have none. I don't know how to create my POJO class for this requirement. Can anybody suggest me a way how to do it?
Unless you don't need anything special, you should design it as like:
public class Student{
private long id;
private String name;
//getters and setters
private Map<String, String> parameters = new HashMap<>();
public void add(String key, String value) {
parameters.put(key, value);
}
public void addAll(Map<String, String> map) {
parameters.putAll(map);
}
}
If you need type safety then the design is little bit complicated a consider using something like:
class StudentParameters {
long param1;
String param2;
}
and Student:
public class Student{
private long id;
private String name;
//getters and setters
private StudentParameters studentParameters;
public setStudentParameters(final StudentParameters studentParameters) {
this.studentParameters = studentParameters;
}
}
Do not create complex hierarchies e.g Map<List<List>, List<List>> it will complicate whole structure.