Whole table not showing in JSON when doing Hibernate mapping - java

The table is created successfully and filled with information in H2 database as seen here:
When using Spring boot to display this table information with JSON format i only see this:
Here you can see the code snippet from the object
package com.share.sharelt.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import lombok.Data;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Entity
#Data
#Table(name = "item_rental")
public class ItemRental {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "created")
private Date created;
#Column(name = "cost")
BigDecimal cost;
#Column(name = "rent_begin")
private Date rentBegin;
#Column(name = "rent_end")
private Date rentEnd;
#Column(name = "is_confirmed")
private boolean isConfirmed;
#JsonBackReference
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "renter_id", nullable = true)
private User user;
public ItemRental(){};
}
The problem is that i want to see the whole table information, more specifically the "renter_id" column

One of the solutions is to create a DTO class which is gonna be a JSON wrapper to your ItemRental entity
Something like ItemRentalDTO and UserDTO with all fields of ItemRental and User entity class
Link: https://www.baeldung.com/entity-to-and-from-dto-for-a-java-spring-application

Related

How can I auto create the associative (or junction) table in many-to-many relationship using JPA Buddy

I am using the JPA Buddy plugin in IntelliJ, and I want to quickly create sql script (MySQL) from the entity class of Student and Course (many-to-many relationship).
I have successfully created the course and student table, but look like JPA Buddy does not have the option to create the associative (junction) table "student_course" (as showed in picture below)? Can JPA Buddy create the associative (junction) table in many-to-many relationship?
Student and Course class for code references:
Student.java
#Table(name = "student")
#Entity
#Getter
#Setter
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "name")
private String name;
#ManyToMany
#JoinTable(name = "student_course",
joinColumns = #JoinColumn(name = "student_id"),
inverseJoinColumns = #JoinColumn(name = "courses_id"))
private Set<Course> courses;
}
Course.java
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.Set;
#Table(name = "course")
#Entity
#Getter
#Setter
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "name")
private String name;
#ManyToMany(mappedBy = "courses")
private Set<Student> students;
}
Thanks for reporting! JPAB-1448 и JPAB-1469 tickets were closed and it works since the 2022.1.0 version of JPA Buddy

How can i add an record by using id reference of other related table?

I've two entities which are named Airport and Route. Route has two field which named startPoint and endPoint. Both of them will be id value of Airport entity. I'm adding two airport entity, after that, I want to add Route by using id values of these airport records. I got an error like that
"message": "JSON parse error: Cannot construct instance of com.finartz.airlines.entity.Airport (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.finartz.airlines.entity.Airport (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1)\n at [Source: (PushbackInputStream); line: 2, column: 18] (through reference chain: com.finartz.airlines.entity.Route[\"startPoint\"])"
these are my entities:
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
#Data
#Builder
#Entity
#Table(name = "airport")
#NoArgsConstructor
#AllArgsConstructor
#EntityListeners(AuditingEntityListener.class)
public class Airport implements Serializable {
private static final long serialVersionUID = -3762352455412752835L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "code")
private String code;
#Column(name = "name")
private String name;
#Column(name = "city")
private String city;
#Column(name = "country")
private String country;
#Column(name = "description")
private String description;
#CreationTimestamp
#Column(name = "created_on", nullable = false, updatable = false)
private LocalDateTime createdOn;
#UpdateTimestamp
#Column(name = "updated_on")
private LocalDateTime updatedOn;
}
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
#Data
#Builder
#Entity
#Table(name = "route")
#NoArgsConstructor
#AllArgsConstructor
#EntityListeners(AuditingEntityListener.class)
#ApiModel(value = "route")
public class Route implements Serializable {
private static final long serialVersionUID = -8451228328106238822L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_start_point",referencedColumnName = "id")
private Airport startPoint;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_end_point",referencedColumnName = "id")
private Airport endPoint;
#CreationTimestamp
#Column(name = "created_on", nullable = false, updatable = false)
private LocalDateTime createdOn;
#UpdateTimestamp
#Column(name = "updated_on")
private LocalDateTime updatedOn;
}
And repository of the Route is below:
import com.finartz.airlines.entity.Route;
import com.finartz.airlines.repository.RouteRepository;
import com.finartz.airlines.util.HibernateUtil;
import lombok.AllArgsConstructor;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
#AllArgsConstructor
public class RouteRepositoryImpl implements RouteRepository {
public Long add(Route route){
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx;
Long routeId;
tx = session.beginTransaction();
routeId = (Long) session.save(route);
tx.commit();
session.close();
return routeId;
}
}
How can I add new Route by using request which provided below?
{
"startPoint":1,
"endPoint":2
}
I would use the session's entity manager to get a reference to an airport from the DB.
Construct using this code whenever you want to create a Route this way:
EntityManagerFactory emf = session.getEntityManagerFactory();
EntityManager em = emf.createEntityManager();
Airport startPoint = em .getReference(Airport.class, startPointID);
Airport endPoint = em .getReference(Airport.class, endPointID);
It should be something like this
session.beginTransaction();
session.save(route);
tx.commit();
Long id = route.getId();
session.close();
return id;
You should not use begin/close transaction. Use Spring Data JPA, it manage transaction session automatically. Your way is not best practices since you use Spring Boot (Let's see https://github.com/donhuvy/library/blob/master/src/main/java/com/example/library/controller/BookController.java#L29 very simple and easy).

JPA OneToOne find all stuck in loop

I've a Java REST API with JPA. Whenever I create an entity, I also want to create another entity with a forgein key. Or maybe someone can advise me otherwise, I would really appreciate it and learn from it =)
When i successfully create a company it will make a file entity in the database as well, so that works fine. but,
Whenever I execute a findAll method in the JPA repository it will give me a loop of the one company that i've created.
like this:
If you need any more information, please let me know!
Company.class
package nl.hulpvriend.dehulpvriend.company;
import javax.validation.constraints.NotNull;
import lombok.*;
import nl.hulpvriend.dehulpvriend.file.File;
import javax.persistence.*;
import javax.validation.constraints.Size;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotNull
private String email;
#Column(unique = true)
#NotNull(message = "The company name cannot be empty")
#Size(max = 30, message = "Company name cannot be longer than 30 characters")
private String name;
#NotNull(message = "Company must contain a service type")
#Enumerated(EnumType.STRING)
private ServiceType serviceType;
private double stars;
private Integer pricePerHour;
private String description;
private String kvk;
#OneToOne(mappedBy="company", cascade = CascadeType.ALL)
private File file;
}
File.class
package nl.hulpvriend.dehulpvriend.file;
import lombok.*;
import nl.hulpvriend.dehulpvriend.company.Company;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
#AllArgsConstructor
#Getter
#Setter
#NoArgsConstructor
#Entity
#Data
public class File {
#Id
private Integer id;
private String fileId;
#OneToOne(fetch = FetchType.EAGER)
#MapsId
private Company company;
#NotNull(message = "Must contain a data")
#Lob
private byte[] data;
private String downloadUrl;
private String fileName;
private String fileType;
public File(String fileName, String fileType, byte[] data) {
this.fileName = fileName;
this.fileType = fileType;
this.data = data;
}
}
Add JsonIgnore to one of the references to break the loop:
For example in the File class:
#JsonIgnore
#OneToOne(fetch = FetchType.EAGER)
#MapsId
private Company company;

Hibernate Field annotation joinColumn set id and get object

Is there anyway to set id and get project object for the below project field using filed annotation. so that i can set only project id while persisting in this child table instead of setting the whole object while persisting since we are going to save only id of project in board_project table. My be a duplicate i couldn't find other links. This is like we are in practice of using filed annotation instead of method.
Using : hibernate5.0 - jpa2.1 lombok(i.e getter/setter) for Spring-data-commons-1.13 for CRUD Operations
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "board_project")
public class BoardProject {
#Id
#SequenceGenerator(name = "board_project_id_generator", sequenceName = "board_project_id_seq", allocationSize = 1)
#GeneratedValue(generator = "board_project_id_generator")
private Long id;
#Column(name = "board_id")
private Long boardId;
#ManyToOne
#JoinColumn(name = "project_id")
private Project project; // field set id and get object
}
Project Entity :
public class Project{
#Id
#SequenceGenerator(name = "project_id_generator", sequenceName = "project_id_seq", allocationSize = 1)
#GeneratedValue(generator = "project_id_generator")
private Long id;
#Column(name = "name")
private String name;
}
Update: Found something like this
#ManyToOne
#JoinColumn(name = "project_id", updatable = false, insertable = false)
private Project project;
#Column(name = "project_id")
#NotNull
private Long projectId;
Don't know is it ok
Any help on this would be great.

How to create a model, in Spring, from json where the foreign key is referenced as a long attribute?

One Group has many Users:
Group
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import java.util.Collection;
import java.util.List;
#Entity
#Table(name = "GROUPS")
public class Group {
#Id
#Column(name = "ID")
private Long ID;
#Column(name = "NAME")
private String NAME;
//#JsonManagedReference
#OneToMany(mappedBy = "group"
//, fetch = FetchType.EAGER
//, cascade = CascadeType.ALL
)
private List<Users> itsUser;
//getters and setters are omitted for clarity
}
Users
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import javax.persistence.*;
import static javax.persistence.GenerationType.SEQUENCE;
#Entity
#Table(name = "USERS")
#SequenceGenerator(name = "SEQUENCE_USER_ID", //my own name in java (unique)
sequenceName = "GENERATOR_SEQUENCE_USERS", //in database
initialValue = 1,
allocationSize = 1)
public class Users {
#JsonProperty(value = "id") //these play a role when both reading or writing
#Id
#Column(name = "ID")
#GeneratedValue(strategy=SEQUENCE, generator="SEQUENCE_USER_ID")
private Long ID;
#JsonProperty(value = "name")
#Column(name="NAME")
private String NAME;
#JsonProperty(value = "username")
#Column(name="USERNAME")
private String USERNAME;
#JsonProperty(value = "password")
#Column(name="PASSWORD")
private String PASSWORD;
#JsonProperty(value = "email")
#Column(name="EMAIL")
private String EMAIL;
#JsonProperty(value = "picture") //Now it works with both mypic and picture as json keys
#Column(name="PICTURE")
private String PICTURE;
//#Column(name="GROUP_ID") //we already have a ManyToOne for this, we cannot repeat it
#JsonProperty(value = "groups_id")
//to ignore it in jpa (http://stackoverflow.com/questions/1281952/jpa-fastest-way-to-ignore-a-field-during-persistence)
private Long itsGroupId;
#Transient
public Long getItsGroupId() {
if(itsGroupId == null) {
this.itsGroupId = group.getID();
} else {
//nop
}
return itsGroupId;
}
public void setItsGroupId(Long itsGroupId) {
this.itsGroupId = itsGroupId;
}
//#JsonIgnore
//#JsonProperty(value = "groups_id")
//#JsonBackReference
#ManyToOne(optional = false, targetEntity = Group.class)
#JoinColumn(
name = "GROUP_ID", //column name
referencedColumnName = "ID" //reference name
)
private Group group;
//getters and setters are omitted for clarity
}
We are using Spring with Spring-data and Jackson to do things automagically but we cannot configure the magic:
We are trying to stick on the following constraints at the same time:
1) Keep the ability to have a reference to the groupId and the ManyToOne relationship group.
This is easy to be achieved by putting #Transient annotation at the groupId because #Column is not allowed since we have already declared the #ManyToOne annotation. You also have to implement the getGroupId method accordingly.
2) Return a json of Users class that contains the groups_id.
This can be implemented by setting the #JsonProperty annotation.
3) Create a user class, and also save it in the database, by a json. The json contains groups_id which has as a value an integer for the foreign key.
This does not work because by setting it #Transient above, then the system refuses to save in the database something that is transient or at least this is how we interpret this exception:
HTTP Status 500 - Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: not-null
property references a null or transient value: com.pligor.mvctest.models.Users.group;
nested exception is org.hibernate.PropertyValueException:
not-null property references a null or transient value: com.pligor.mvctest.models.Users.group
On the backend do something like this:
Group group = groupRepository.findById(userResource.getGroupId());
if (group != null) {
User user = new User(userResource);
user.setGroup(group);
userRepository.save();
}
The idea behind this is that you need to fetch the group from the DB, to be able to link it with the newly created User

Categories