Nested JSON in JSON - java

How can I form JSON like that:
{
"error": false,
"errorCode": 0,
"message": [{
"id": "93",
"venueName": "Sushi Kuni",
"venueAddress": "10211 S De Anza Blvd Cupertino CA",
"showDate": "1531022400",
"showTime": "",
"description": ""
}, {
"id": "38",
"venueName": "Two Keys Tavern",
"venueAddress": "333 S Limestone Lexington KY",
"showDate": "1531368000",
"showTime": "8 pm - 1 am",
"description": ""
}]
}
I tried creating models with one-to-one, many-to-one relationships.
#Entity
#Table(name = "tutorials")
public class Tutorial {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tutorial_generator")
private int id;
#Column(name = "title")
private String title;
#Column(name = "description")
private String description;
#Column(name = "published")
private boolean published;
#Entity
#Table(name = "comments")
public class Comment {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "comment_generator")
private int id;
#Lob
private String content;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "tutorial_id", nullable = false)
#JsonIgnore
private Tutorial tutorial;
Controller:
public ResponseEntity<List<Comment>> getAllCommentsByTutorialId(#PathVariable(value = "tutorialId") int tutorialId) {
if (!tutorialRepository.existsById(tutorialId)) {
throw new ResourceNotFoundException("Not found Tutorial with id = " + tutorialId);
}
List<Comment> comments = commentRepository.findByTutorialId(tutorialId);
return new ResponseEntity<>(comments, HttpStatus.OK);
}
But I got
[
{
"id": 1,
"content": "asdaasfaf"
},
{
"id": 3,
"content": "ssaduy7tjyjt"
},
{
"id": 4,
"content": null
}
]
I read about creating nodes, but didn't understand, how integrate it with spring data.
What i need to nest table Comments in table Tutorials?

Looks to me as if you are pretty close to the desired outcome.
First of all you should add a member to your Tutorial entity:
#OneToMany(mappedBy = "tutorial_id")
private List<Comment> comments;
And the final missing part is making your controller return a tutorial instance:
public ResponseEntity<Tutorial> getTutorialWithComments(#PathVariable(value = "tutorialId") int tutorialId) {
Tutorial tutorial = tutorialRepository.findById(tutorialId)
.orElseThrows(() -> new ResourceNotFoundException("Not found Tutorial with id = " + tutorialId));
return new ResponseEntity<>(tutorial, HttpStatus.OK);
}
I wrote this without any IDE assistance, so please excuse any mistakes. The idea should be clear though, you need to return a tutorial that contains a list of comments.

Related

Many to many json request

A Contract has several AbsenceType, and an AbsentType can be in several different Contracts. So I made a manyToMany relation in both classes.
Entity
#Table(name = "contract")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
#EntityListeners(AuditingEntityListener.class)
public class Contract {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
#Column(name = "employee")
private int employee;
#ManyToMany(mappedBy = "contracts")
private List<AbsenceType> absence_types;
// ... getteur setteur contructor
#Entity
#Table(name = "absence_type")
#EntityListeners(AuditingEntityListener.class)
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class AbsenceType {
#Id
#GeneratedValue
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
// hexa : #FFFFFF
#Column(name = "color")
private String color;
#Column(name = "is_paid")
private boolean is_paid;
#ManyToMany
#Column(name = "contracts")
private List<Contract> contracts;
// ... getteur setteur contructor
I want to be able to create empty Absence types and then when I create a contract, give in my json, the previously created absenceType and not create a new AbsenceType.
In the idea I do this:
{
"id": 1 # Exemple, in real in don't had id on json
"name": "Congé sans solde",
"color": "ff4040",
"is_paid": false,
"contracts": []
}
and after ->
{
"name": "Contract4",
"employee": 3,
"absence_types" : [
{
"id":1
}
]
}
But the response when i get all contracts is:
{
"id": 621,
"name": "Contract4",
"employee": 3,
"absenceTypes": []
}
But i want :
{
"id": 621,
"name": "Contract4",
"employee": 3,
"absenceTypes": [
{
"id": 1,
"name": "Congé sans solde",
"color": "ff4040",
"contracts" : [ dudo, i don't think about infinite recursion problem for the moment haha]
}
}
For all of my DAO i have a generic class, how look like this
public void save(T obj) {
Session session = openSession();
Transaction transaction = session.beginTransaction();
session.saveOrUpdate(obj);
transaction.commit();
session.close();
}
and on my Contract controller
#PostMapping("")
public ResponseEntity<String> create(#RequestBody Contract contract) {
// Error 422 if the input role variable is null
if (contract == null)
new ResponseEntity<String>("Can't create null absenceType", HttpStatus.UNPROCESSABLE_ENTITY);
contractDAO.save(contract);
return new ResponseEntity<>("absenceType saved !", HttpStatus.OK);
}

One-Many Relationship in Jpa

I want to get data from my entity with 1-M relationships.
Users have an entity for cv information.With JpaRepo,
Cv class :
#Entity
#Table(name = "cvs")
#Data
#AllArgsConstructor
#NoArgsConstructor
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler", "educations", "works", "langueges", "technologies"})
public class CV {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
//ToDo : Employee bilgilerinin görünmesi problemi giderilecek.
#OneToOne
#JoinColumn(name = "employee_id")
private Employee employee;
#OneToMany(mappedBy = "cv", cascade = CascadeType.ALL, orphanRemoval = true)
List<Education> educations;
#OneToMany(mappedBy = "cv", cascade = CascadeType.ALL, orphanRemoval = true)
List<Work> works;
#OneToMany(mappedBy = "cv", cascade = CascadeType.ALL, orphanRemoval = true)
List<Languege> langueges;
#OneToMany(mappedBy = "cv", cascade = CascadeType.ALL, orphanRemoval = true)
List<Technology> technologies;
#Column(name = "github")
private String github;
#Column(name = "linkedin")
private String linkedin;
#NotNull
#NotBlank
#Column(name = "cover_letter")
private String coverLetter;
#Column(name = "photo")
private String photo;
}
This is Education class (work, languege, technology classes same):
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "cv_educations")
public class Education {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#NotNull
#NotBlank
#Column(name = "school_name")
private String schoolName;
#NotNull
#NotBlank
#Column(name = "department")
private String department;
#NotNull
#NotBlank
#PastOrPresent
#Column(name = "starting_date")
#DateTimeFormat(pattern = "yyyy-mm-dd")
private LocalDate startingDate;
#NotBlank
#Column(name = "graduation_date")
#DateTimeFormat(pattern = "yyyy-mm-dd")
private LocalDate graduationDate;
#ManyToOne
#JoinColumn(name = "cv_id")
private CV cv;
}
I tried to build the following structure with jpa, but the constructer takes list parameter. I got an error because I couldn't write it with jpql
public interface CvRepository extends JpaRepository<CV, Integer> {
#Query("select new com.demo.humanresourcesmanagementsystem.Entities.concretes.CV" +
"(employee.firstName, employee.lastName, cv.github, cv.linkedin, cv.coverLetter," +
"educations, works, langueges, technologies)" +
"from CV cv inner join cv.employee employee inner join cv.educations educations " +
"inner join cv.works works inner join cv.langueges langueges " +
"inner join cv.technologies technologies where cv.employee.id =:employeeId")
CV findByCv(int employeeId);
}
I'd like to read about the educations, works, langueges and technologies in this entity. This means that there will be one cv as output, but there may be more than one education object within the cv (such as primary school, high school), and the incoming data will be in the following format, for example:
"firstName": "X",
"lastName" : "X",
"educations" : [
"education1" {
"school" : "x",
"department" : "x" ...},
"education2" {
"school" : "x",
"department" : "x"...}
"works" : [
"work1" {
"workplace" : "x",
"job" : "x" ...
}
]
"github" : "x",
"linkedin" : "x"
How do i set up this structure with the jpa repository? What kind of dto should I write if I'm gonna use it? Thanks.
UPDATE
When i use spring jpa derivered query (findByEmployeeId) i receive data with this format :
{
"success": true,
"message": "string",
"data": {
"id": 0,
"employee": {
"id": 0,
"email": "string",
"password": "string",
"firstName": "string",
"lastName": "string",
"nationalIdentity": "string",
"yearOfBirth": 0
},
"github": "string",
"linkedin": "string",
"coverLetter": "string",
"photo": "string"
}
}
So i cant receive data for education, work, languege and technology.
It seems you're trying to retrieve a CV by its employer.id. In that case, you can really just use the JPA query method containing keywords. In this case it would look like:
CV findByEmployeeId(int employeeId);
This should return the complete CV object as you would expect.
See here for more details on JPA query method keywords.

How to combine two lists from the same relation in Java-8

I have below entities Manager and Colleague
Manager Entity
#Entity
#Table(name = "Manager")
#Data
public class Manager implements java.io.Serializable {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToMany
#JoinColumn(name = "id")
private List<Colleague> colleagues;
}
Colleague Entity
#Entity
#Table(name = "Colleague")
#Data
public class Colleague implements java.io.Serializable {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
}
Above relation can be represented in JSON as
[
{
"id": "101",
"name": "manager1",
"colleagues": [
{
"id": "101",
"name": "colleague1"
},
{
"id": "101",
"name": "colleague2"
}
]
},
{
"id": "101",
"name": "manager2",
"colleagues": [
{
"id": "101",
"name": "colleague3"
},
{
"id": "101",
"name": "colleague4"
}
]
}
]
I am retrieving the result on managerReposiotry.findAll() as
List<Manager> managerList = managerReposiotry.findAll();
I want to create a super list of all names from Manager and Colleague
What I am currently doing is
List<String> names = new ArrayList<>();
managerList.stream()
.forEach(manager -> {
List<String> nameList =
manager.getColleagues().stream()
.map(colleague -> colleague.getName())
.collect(Collectors.toList());
names.addAll(nameList);
}
);
Is there any other way in Java-8 to improve the above code?
Thank you !!
You can use flatMap to flatten all Colleague of Manager then map Colleague name only and collect as list.
List<String> names =
managerList.stream() // ...Stream<Manager>
.flatMap(m -> m.getColleagues().stream()) // ...Stream<Colleague>
.map(c-> c.getName()) // ...Stream<String>
.collect(Collectors.toList());
But the better way is directly fetched from the database if all colleagues have manager.
#Query("select c.name from Colleagues c")
List<String> findAllColleagueName();

Spring Boot Can't get the relation entity with findAll or findByColumnName method

I'm just trying to test the relation #ManyTonOne in Spring Boot (Spring Data JPA)n so I've created two simple Class Book and Author
Here is the Class Book and Author :
#Entity
#Table(name = "book")
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "title")
private String title;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "author_id", nullable = false)
#JsonIgnore
//#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
private Author author;
Class Author:
#Entity
#Table(name = "author")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "fullname")
private String fullame;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "author", fetch = FetchType.LAZY)
private Set<Book> books;
I just want when i try to call findAll() for books i get author also, when i make it by default i get this result without the author :
"_embedded": {
"books": [
{
"title": "Book1",
"_links": {
"self": {
"href": "http://localhost:8080/api/books/1"
},
"book": {
"href": "http://localhost:8080/api/books/1"
}
}
},
Or when i write directly method findAll in controller :
#RestController
public class BookRestController {
#Autowired
BookRepository bookRepo;
#RequestMapping("/books1/")
public List<Book> createInvoice() {
List<Book> list = bookRepo.findAll();
System.out.println(list);
return list;
}
i get this result :
[
{
"id": 1,
"title": "Book1"
},
{
"id": 2,
"title": "Book2"
},
I've tried also to search by title findByTitle(string), I don't get the author also
A different example that I found is about the second relation #OneToMany, not the other way
What I must add in my Entity or repository or controller to retrieve (with a good way) the author id?
I think without the JsonIgnore maybe you're just going right into recursion hell, since the book has an author and the author has minimum this book, and the book has the author...
Try a getter on the AuthorId, something like
public Long getAuthorId() {
return (author == null) ? null : author.getId());
}
EDIT:
wrote the maybe before your comment, now I'm quite sure :-)
Remove #JsonIgnore and use #JsonIdentityInfo on both classes to get author also for every book.
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Book {
...
}
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class Author {
...
}

Spring Boot return null value for the relational entity after save

I'm Working On a Spring Boot Application and I have two Entities AdminUsers And Blogs, These two Entities have OneToMany relationship and I wanted to Return all Blogs after save a blog, as follows
#PostMapping("/add")
#ResponseBody
public List<Blog> addBlog(#RequestBody Blog blog) {
Blog savedBlog = blogService.save(blog);
return blogService.findAllBlogs();
}
The problem I'm facing is tt returns null for the last inserted Blog's AdminUser all the time as follows,
[
{
"id": 30,
"adminid": 1,
"blogcontent": "blog dddcontent",
"blogtitle": "titleaa",
"datetime": "1111-12-31 23:59:59",
"adminUser": {
"adminid": 1,
"adminusername": "admin",
"adminemail": "admin#kongcepts.com",
"adminpassword": "$2a$10$3aVlo8BkGbKQYzMDMDZTi.6dQavPeY8j0yD833ldA4utNAE4SxzpC",
"status": 1,
"attempts": 0,
"resetToken": "$2a$10$6o7N/u4pgwjWya30wueVve9oqPNO6TTLidOg6NincqL5lOvLh03oa"
}
},
{
"id": 31,
"adminid": 1,
"blogcontent": "blog dddcontent",
"blogtitle": "titleaa",
"datetime": "1111-12-31 23:59:59",
"adminUser": null
}
]
But when I hit this endpoint after that
#GetMapping("/get/blogs")
public List<Blog> listAllBlogs() {
return blogService.findAllBlogs();
}
It returns as expected
[
{
"id": 30,
"adminid": 1,
"blogcontent": "blog dddcontent",
"blogtitle": "titleaa",
"datetime": "1111-12-31 23:59:59",
"adminUser": {
"adminid": 1,
"adminusername": "admin",
"adminemail": "admin#kongcepts.com",
"adminpassword": "$2a$10$3aVlo8BkGbKQYzMDMDZTi.6dQavPeY8j0yD833ldA4utNAE4SxzpC",
"status": 1,
"attempts": 0,
"resetToken": "$2a$10$6o7N/u4pgwjWya30wueVve9oqPNO6TTLidOg6NincqL5lOvLh03oa"
}
},
{
"id": 31,
"adminid": 1,
"blogcontent": "blog dddcontent",
"blogtitle": "titleaa",
"datetime": "1111-12-31 23:59:59",
"adminUser": {
"adminid": 1,
"adminusername": "admin",
"adminemail": "admin#kongcepts.com",
"adminpassword": "$2a$10$3aVlo8BkGbKQYzMDMDZTi.6dQavPeY8j0yD833ldA4utNAE4SxzpC",
"status": 1,
"attempts": 0,
"resetToken": "$2a$10$6o7N/u4pgwjWya30wueVve9oqPNO6TTLidOg6NincqL5lOvLh03oa"
}
}
]
Here is my Entity classes for AdminUser and Blogs
Admin User
#Entity
#Table(name = "tbl_admin")
public class AdminUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "admin_id")
private Integer adminid;
#Column(name = "admin_username", nullable = false)
private String adminusername;
#Column(name = "admin_email", nullable = false)
private String adminemail;
#Column(name = "admin_password", nullable = false)
private String adminpassword;
#Column(name = "admin_status")
private Integer status = 1;
#Column(name = "admin_attempt")
private Integer attempts = 0;
#Column(name = "admin_reset_token")
private String resetToken;
#OneToMany(mappedBy = "adminUser")
#JsonIgnore
private List<Blog> blog;
and Blog
#Entity
#Table(name = "tbl_blog")
public class Blog {
#Id
#Column(name = "blog_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "admin_id")
private Integer adminid;
#Column(name = "blog_content")
private String blogcontent;
#Column(name = "blog_title")
private String blogtitle;
#Column(name = "blog_datetime")
private String datetime;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "admin_id", updatable = false, insertable = false)
private AdminUser adminUser;
I finally figure it out that, for some reasons it didn't worked previously because i was only giving the value to the join column named adminid #JoinColumn(name = "admin_id", updatable = false, insertable = false), all i wanted to do search the relation entity with
AdminUser addedUser = adminService.findbyid(Integer id);
and added the result to the blog's relational entity(admin property),
so final code ends up with something like this.
#PostMapping("/add")
#ResponseBody
public List<Blog> addBlog(#RequestBody Blog blog) {
AdminUser addedAdmin = adminService.findbyid(blog.getAdminid());
blog.setAdminuser(addedAdmin);
blogService.save(blog);
return blogService.findAllBlogs();
}
Try annotating your save() method in blogService with #Transactional

Categories