I have this part of database schema:
and this User entity:
#Entity
#Table(name = "user", catalog = "ats")
public class User implements java.io.Serializable{
private static final long serialVersionUID = 1L;
private String username;
private boolean enabled;
private Role role;
private ClientVersion clientVersion;
private ClientLicense clientLicense;
#JsonIgnore
private Set<NotificationHasUser> notificationHasUsers = new HashSet<NotificationHasUser>(0);
public User() {
}
public User(String username, boolean enabled) {
this.username = username;
this.enabled = enabled;
}
public User(String username, boolean enabled, Role role, Set<NotificationHasUser> notificationHasUsers) {
this.username = username;
this.enabled = enabled;
this.role = role;
this.notificationHasUsers = notificationHasUsers;
}
#Id
#Column(name = "username", unique = true, nullable = false, length = 45)
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "enabled", nullable = false)
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_role", nullable = false)
public Role getRole() {
return this.role;
}
public void setRole(Role role) {
this.role = role;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_clientVersion", nullable = false)
public ClientVersion getClientVersion() {
return this.clientVersion;
}
public void setClientVersion(ClientVersion clientVersion) {
this.clientVersion = clientVersion;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.user")
public Set<NotificationHasUser> getNotificationHasUser() {
return this.notificationHasUsers;
}
public void setNotificationHasUser(Set<NotificationHasUser> notificationHasUsers) {
this.notificationHasUsers = notificationHasUsers;
}
#OneToOne(fetch = FetchType.LAZY, mappedBy = "user")
public ClientLicense getClientLicense(){
return this.clientLicense;
}
public void setClientLicense(ClientLicense clientLicense){
this.clientLicense = clientLicense;
}
}
All works fine until I add a new clientlicense. If I add this I receive an infinite loop:
Could not write content: Infinite recursion (StackOverflowError) (through reference chain: com.domain.User["clientLicense"]->com.domain.ClientLicense["user"]->com.domain.User["clientLicense"]->com.domain.ClientLicense["user"]->com.domain.User["clientLicense"]->com.domain.ClientLicense["user"]->com.domain.User["clientLicense"]->com.domain.ClientLicense["user"]->com.domain.User["clientLicense"]-....
This is my ClientLicense entity
#Entity
#Table(name = "clientlicense", catalog = "ats")
public class ClientLicense implements java.io.Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private Integer idClientLicense;
private Date startDate;
private Date endDate;
private int counter;
private String macAddress;
private String cpuId;
private User user;
public ClientLicense() {
}
/**
* #param startDate
* #param endDate
* #param counter
* #param macAddress
* #param cpuId
* #param users
*/
public ClientLicense(Date startDate, Date endDate, int counter, String macAddress, String cpuId, User user) {
super();
this.startDate = startDate;
this.endDate = endDate;
this.counter = counter;
this.setMacAddress(macAddress);
this.setCpuId(cpuId);
this.user = user;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id_clientLicense", unique = true, nullable = false)
public Integer getIdClientLicense() {
return this.idClientLicense;
}
public void setIdClientLicense(Integer idClientLicense) {
this.idClientLicense = idClientLicense;
}
#Column(name = "startDate", nullable = false)
public Date getStartDate() {
return this.startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
#Column(name = "endDate", nullable = false)
public Date getEndDate() {
return this.endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
#Column(name = "counter", nullable = false)
public int getCounter() {
return this.counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
/**
* #return the macAddress
*/
#Column(name = "macAddress", nullable = false)
public String getMacAddress() {
return macAddress;
}
/**
* #param macAddress the macAddress to set
*/
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
/**
* #return the cpuId
*/
#Column(name = "cpuId", nullable = false)
public String getCpuId() {
return cpuId;
}
/**
* #param cpuId the cpuId to set
*/
public void setCpuId(String cpuId) {
this.cpuId = cpuId;
}
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "id_username")
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
}
This is my first OneToOne relationship, what is the correct annotation that I have to use? I read some example but I don't understand fine, they are different each other.
try something like this.
public class User {
private ClientLicense clientLicense;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "user")
public ClientLicense getClientLicense() {
return this.clientLicense;
}
}
public class ClientLicense {
private User user;
#OneToOne
#JoinColumn(name = "id_username")
public User getUser() {
return this.user;
}
}
The problem is that the two entities have no way of finding out that the two fields are actually specifying a single relationship. So hibernate assumes that they are not the same relationship and therefore tries to fetch them (because one-to-one relationships are fetched eagerly by default).
Add #OneToOne(mappedBy = "user") before the clientLicense field in the User class to tell hibernate that this field is "mapped by" the same column as the user field in the ClientLicense class
Related
i'm new in spring.I have a project that name is SampleStore. some entities created in my projects, such as User, UserRole, Product, Orders, CartItem and .... but i have a problem. when i try add new user app does it without error and new record inserted in databse. but when i try to insert new order i'll get error.
User.java
#Entity
#Table(name = "users")
public class User implements Serializable, UserDetails {
private static final long serialVersionUID = -8245107356306518473L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
#Column(name = "username", nullable = false, unique = true, length = 50)
private String username;
#Column(name = "password", nullable = false, length = 60)
private String password;
#Column(name = "enabled", nullable = true, columnDefinition = "tinyint(1) default 1")
private boolean enabled;
#Column(name = "expired", nullable = true, columnDefinition = "tinyint(1) default 1")
private boolean accountNonExpired;
#Column(name = "locked", nullable = true, columnDefinition = "tinyint(1) default 1")
private boolean accountNonLocked;
#Column(name = "credential", nullable = true, columnDefinition = "tinyint(1) default 1")
private boolean credentialsNonExpired;
#Column(name = "gender", nullable = true)
private char gender;
#Column(name = "address", nullable = true)
private String address;
#Column(name = "phonenumber", nullable = true)
private String phoneNumber;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
private Set<UserRole> userRoles = new HashSet<UserRole>(0);
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
private List<Comment> comments = new ArrayList<Comment>();
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
private List<Orders> orders = new ArrayList<Orders>();
public User() {
}
public User(String username, String password, boolean enabled) {
this.username = username;
this.password = password;
this.enabled = enabled;
}
public User(String username, String password, boolean enabled, Set<UserRole> userRoles) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.userRoles = userRoles;
}
public User(String username, String password, boolean enabled, boolean accountNonExpired,
boolean credentialsNonExpired, boolean accountNonLocked, Set<UserRole> authorities) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.accountNonExpired = accountNonExpired;
this.credentialsNonExpired = credentialsNonExpired;
this.accountNonLocked = accountNonLocked;
this.userRoles = authorities;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public Set<UserRole> getUserRoles() {
return userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public List<Comment> getComments() {
return comments;
}
public void setComments(List<Comment> comments) {
this.comments = comments;
}
public List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
#Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", enabled=" + enabled
+ ", gender=" + gender + ", address=" + address + ", phoneNumber=" + phoneNumber + ", userRoles="
+ userRoles + "]";
}
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
for (UserRole userRole : userRoles) {
setAuths.add(new SimpleGrantedAuthority(userRole.getRole()));
}
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(setAuths);
return result;
}
public boolean isAccountNonExpired() {
return accountNonExpired;
}
public boolean isAccountNonLocked() {
return accountNonLocked;
}
public boolean isCredentialsNonExpired() {
return credentialsNonExpired;
}
public void setAccountNonExpired(boolean accountNonExpired) {
this.accountNonExpired = accountNonExpired;
}
public void setAccountNonLocked(boolean accountNonLocked) {
this.accountNonLocked = accountNonLocked;
}
public void setCredentialsNonExpired(boolean credentialsNonExpired) {
this.credentialsNonExpired = credentialsNonExpired;
}
}
UserRole.java
#Entity
#Table(name = "user_roles", uniqueConstraints = #UniqueConstraint(columnNames = { "username", "role" }))
public class UserRole {
private Integer userRoleId;
private User user;
private String role;
public UserRole() {
}
public UserRole(User user, String role) {
this.user = user;
this.role = role;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_role_id", unique = true, nullable = false)
public Integer getUserRoleId() {
return this.userRoleId;
}
public void setUserRoleId(Integer userRoleId) {
this.userRoleId = userRoleId;
}
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = false)
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
#Column(name = "role", nullable = false, length = 45)
public String getRole() {
return this.role;
}
public void setRole(String role) {
this.role = role;
}
}
Orders.java
#Entity
#Table(name = "orders")
public class Orders implements Serializable {
private static final long serialVersionUID = -3672662224925418969L;
#Id
#Column(name = "ord_id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#DateTimeFormat(pattern = "yyyy-mm-dd")
#Column(name = "orderDate", nullable = false)
private Date orderDate;
#DateTimeFormat(pattern = "yyyy-mm-dd")
#Column(name = "delivery", nullable = false)
private Date deliveryDate;
#Column(name = "success", nullable = true, columnDefinition = "tinyint(1) default 0")
private boolean success;
#Column(name = "cancel", nullable = true, columnDefinition = "tinyint(1) default 0")
private boolean canceled;
#Column(name = "cause", nullable = true)
private String cancelCause;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "order")
private List<CartItem> items = new ArrayList<CartItem>();
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="username",nullable=false)
private User user;
public Orders() {
}
public Orders(Date deliveryDate, List<CartItem> items, User user) {
this.orderDate = new Date();
this.deliveryDate = deliveryDate;
this.items = items;
this.user = user;
}
public Orders(List<CartItem> items, User user) {
this.orderDate = new Date();
this.items = items;
this.user = user;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getOrderDate() {
return orderDate;
}
public void setOrderDate(Date orderDate) {
this.orderDate = orderDate;
}
public Date getDeliveryDate() {
return deliveryDate;
}
public void setDeliveryDate(Date deliveryDate) {
this.deliveryDate = deliveryDate;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public boolean isCanceled() {
return canceled;
}
public void setCanceled(boolean canceled) {
this.canceled = canceled;
}
public String getCancelCause() {
return cancelCause;
}
public void setCancelCause(String cancelCause) {
this.cancelCause = cancelCause;
}
public List<CartItem> getItems() {
return items;
}
public void setItems(List<CartItem> items) {
this.items = items;
}
}
CartItem.java
#Entity
#Table(name = "saleitems", uniqueConstraints = {})
public class CartItem implements Serializable {
private static final long serialVersionUID = 7968604053015663078L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false)
private Long id;
#Column(name = "prd_id", nullable = false)
private Product product;
#Column(name = "quantity", nullable = false, columnDefinition = "int(11) default 1")
private Integer quantity;
#Column(name = "totalprice", nullable = false)
private BigDecimal totalprice;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "orderid", nullable = false)
private Orders order;
public CartItem(Product product, Integer quantity) {
this.product = product;
this.quantity = quantity;
setTotalprice();
}
public CartItem() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public BigDecimal getTotalprice() {
return totalprice;
}
public void setTotalprice() {
this.totalprice = getProduct().getPrice().multiply(new BigDecimal(getQuantity()));
}
public Orders getOrder() {
return order;
}
public void setOrder(Orders order) {
this.order = order;
}
}
here one part of my controller code that user to save new user and save new order.
#RequestMapping(value = "/saveuser", method = RequestMethod.POST)
public ModelAndView saveNewUser(#ModelAttribute User user) {
ModelAndView model = new ModelAndView();
user.setEnabled(true);
user.setAccountNonExpired(true);
user.setAccountNonLocked(true);
user.setCredentialsNonExpired(true);
UserRole role = new UserRole(user, "ROLE_USER");
Set<UserRole> roles = new HashSet<UserRole>();
roles.add(role);
user.setUserRoles(roles);
String result = userService.addUser(user);
if (!result.toLowerCase().startsWith("error")) {
model.setViewName("loginForm");
} else {
model.setViewName("newuser");
model.addObject("error", result);
}
return model;
}
#SuppressWarnings("unchecked")
#RequestMapping(value = "/store/addorder", method = RequestMethod.GET)
public ModelAndView addOrder(HttpSession session) {
ModelAndView model = new ModelAndView();
// create list of products that we have to add in orders
System.err.println("item get to retrieving---------------");
List<CartItem> items = (List<CartItem>) session.getAttribute("cart");
for (CartItem cartItem : items) {
System.err.println(cartItem.getProduct());
}
// find user by username to set orders userinfo
System.err.println("user information get to retriving---------------");
String username = SecurityContextHolder.getContext().getAuthentication().getName();
User user = userService.findByUsername(username);
System.err.println(user);
// new order generated and setter methods invoke
System.err.println("new order generated-------------------");
Orders order = new Orders(items, user);
Date d = new Date();
Date delivery = StoreUtils.deliveryDate(d, 3);
order.setOrderDate(d);
order.setDeliveryDate(delivery);
order.setUser(user);
order.setItems(items);
String addOrders = orderService.addOrders(order);
System.err.println("new order add status " + addOrders + "-------------");
System.err.println(order);
// change product quantity after adding new order
for (int i = 0; i < items.size(); i++) {
Integer qSale = items.get(i).getQuantity() * (-1);
productService.rechargeProduct(items.get(i).getProduct(), qSale);
}
if (!addOrders.toLowerCase().contains("error")) {
model.setViewName("successorder");
model.addObject("order", order);
model.addObject("message", addOrders);
session.setAttribute("cart", null);
} else {
session.setAttribute("error", addOrders);
model.setViewName("redirect:/addtocartlist");
}
return model;
}
finally, here my code in dao class that save user and order.
UserDaoImpl.java
public String addUser(User user) {
String result = "";
String pass = encoder.encode(user.getPassword());
user.setPassword(pass);
try {
session().save(user);
session().flush();
result = "success";
} catch (Exception e) {
if (e.getCause().getMessage().toLowerCase().contains("duplicate"))
result = "error :user is already joined to store!";
else
result = "error :" + e.getCause().getMessage();
}
return result;
}
OrderDaoImpl.java
public String addOrders(Orders orders) {
String result = "";
try {
session().save(orders);
result = "success";
} catch (Exception e) {
if (e.getCause() != null)
if (e.getCause().getMessage().toLowerCase().contains("duplicate"))
result = "error this order already was exist";
else
result = "error " + e.getCause().getMessage();
else {
result = "error " + e.getMessage();
}
System.err.println(result);
} finally {
session().clear();
}
return result;
}
All codes are similar, but results are diffrent. when try to add new order I get this exception:
not-null property references a null or transient value:com.softup.store.entity.CartItem.order
Set both sides of relation. On every item call setOrder(). On user setOrder() also.
I am trying to left join a second table but it doesn't show up. It just gives me all users instead of all users along with the FinishedExams.
This is the method in my repository:
public interface IUserRepository extends CrudRepository<User, Integer> {
#Query("SELECT u FROM User u LEFT JOIN FinishedExam f ON u.id = f.user")
List<User> getAllWithExams();
}
In my FinishedExamController:
#Autowired
private IFinishedExamRepository finishedExamRepository;
#Autowired
private IUserRepository userRepository;
#GetMapping("/allUsersWithExams")
#Fetch(FetchMode.SELECT)
public Iterable<User> getAllUsersWithTheirExams()
{
return userRepository.getAllWithExams();
}
My User model:
#Entity
#Table(name = "users")
public class User implements Serializable {
#Id
#GeneratedValue()
#Column(name = "id")
private int id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "role_id", nullable = false)
public Role role;
public String getStudentNumber() {
return studentNumber;
}
public void setStudentNumber(String studentNumber) {
this.studentNumber = studentNumber;
}
#Column(name = "student_number", nullable = true)
private String studentNumber;
#Column(name = "first_name", nullable = true)
private String firstName;
#Column(name = "last_name", nullable = true)
private String lastName;
#Column(name = "email", nullable = true, unique = true)
private String email;
#OneToOne(fetch = FetchType.EAGER, mappedBy = "user")
private FinishedExam finishedExam;
#JsonIgnore
#Column(name = "password", nullable = true)
private String password;
#Column(name = "created_at")
private LocalDateTime createdAt;
#Column(name = "updated_at")
private LocalDateTime updatedAt;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "event_users",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "event_id", referencedColumnName = "id")
)
#PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
#PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = createdAt;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
public String getRole() {
return role.getName();
}
public void setRole(Role role) {
this.role = role;
}
}
Finished exams model:
#Entity
#Table(name = "finished_exams")
public class FinishedExam implements Serializable {
#Id
#GeneratedValue()
#Column(name = "id")
private int id;
#OneToOne(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "exam_id")
private Exam exam;
#Column(name = "finishedExam", nullable = false)
private String finishedExam;
#Column(name = "created_at")
private LocalDateTime createdAt;
#Column(name = "updated_at")
private LocalDateTime updatedAt;
#PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = createdAt;
}
#PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
public int getId() {
return id;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Exam getExam() {
return exam;
}
public void setExam(Exam exam) {
this.exam = exam;
}
public String getFinishedExam() {
return finishedExam;
}
public void setFinishedExam(String finishedExam) {
this.finishedExam = finishedExam;
}
public void setId(int id) {
this.id = id;
}
public LocalDateTime getCreatedAt() {
return createdAt;
}
public void setCreatedAt(LocalDateTime createdAt) {
this.createdAt = createdAt;
}
public LocalDateTime getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(LocalDateTime updatedAt) {
this.updatedAt = updatedAt;
}
}
I can put whatever I want in the ON clause but nothing changes.
You need to provide a path from your entity to target entity to join:
Replace the query
#Query("SELECT u FROM User u LEFT JOIN FinishedExam f ON u.id = f.user")
with
#Query("SELECT u FROM User u LEFT JOIN u.finishedExam f ON u.id = f.user.id")
I can put whatever I want in the ON clause but nothing changes.
Of course nothing changes. You are performing a left join across a 1:1 relationship, selecting (only) the left entity, and not placing any filter criteria on that entity. The join criteria (and indeed the join itself) don't matter: your query is equivalent to SELECT u FROM User u.
Did you perhaps mean to perform an inner join instead?
I have a problem. Here my entities user and userRole
User
package com.springapp.model;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "users", catalog = "users")
public class User {
private String username;
private String password;
private boolean enabled;
private String email;
private String token;
private Set<UserRole> userRole = new HashSet<UserRole>(0);
public User() {
this.enabled=false;
}
#Column(name = "token",
nullable = false, length = 80)
public String getToken() {
return this.token;
}
public void setToken(String token) {
this.token = token;
}
public String getEmail() {
return this.email;
}
#Column(name = "email",
nullable = false, length = 80)
public void setEmail(String email) {
this.email = email;
}
#Id
#Column(name = "username", unique = true,
nullable = false, length = 45)
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "password",
nullable = false, length = 60)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name = "enabled", nullable = false)
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
public Set<UserRole> getUserRole() {
return this.userRole;
}
public void setUserRole(Set<UserRole> userRole) {
this.userRole = userRole;
}
}
UserRole
package com.springapp.model;
import javax.persistence.*;
import static javax.persistence.GenerationType.IDENTITY;
#Entity
#Table(name = "user_roles", uniqueConstraints = #UniqueConstraint(
columnNames = { "role", "username" }))
public class UserRole{
private Integer userRoleId;
private User user;
private String role;
public UserRole() {
}
public UserRole(User user, String role) {
this.user = user;
this.role = role;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "user_role_id",
unique = true, nullable = false)
public Integer getUserRoleId() {
return this.userRoleId;
}
public void setUserRoleId(Integer userRoleId) {
this.userRoleId = userRoleId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = false)
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
#Column(name = "role", nullable = false, length = 45)
public String getRole() {
return this.role;
}
public void setRole(String role) {
this.role = role;
}
}
Now I want to get list of users with lists of their roles to json using gson lib
List<User> users = userService.showAllUsers();
Gson gson = new Gson();
return gson.toJson(users);
But it fails with stackoverflow error. I think it's because every user refers to roles and roles refers to users (because we have User user in Userroles and Set of roles in users). And it turns "recursion". How can I avoid this error?
That happens when you bidirectional associations and JSon doesn't ignore one side.
You need to mark the many-to-one side with #JsonIgnore:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = false)
#JsonIgnore
public User getUser() {
return this.user;
}
I have a User and Follower, I'm not very familiar with jsp and would like to add a follow button on the frontend and add the current user to the Follwers table and display follwers on the user profile which is already done.
How would I go about this?
Follower :
#Entity
public class Follower {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
User:
#Entity
#Table(name = "usr", indexes = { #Index(columnList = "email", unique = true) })
// using usr because in may conflict with the name of the class
public class User {
public static final int EMAIL_MAX = 250;
public static final int NAME_MAX = 50;
/*
* public static enum Role {
*
* UNVERIFIED, BLOCKED, ADMINISTRATOR
*
* }
*/
// primary key long, needs to be annotated with #Id
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// add columns
#Column(nullable = false, length = EMAIL_MAX)
private String email;
#Column(nullable = false, length = NAME_MAX)
private String name;
// no length, the password will be encrypted to some longer value than the
// user enters
#Column(nullable = false)
private String password;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
private List<Tweets> tweets;
#OneToMany(mappedBy = "user")
private List<Follower> followers;
public List<Follower> getFollowers() {
return followers;
}
public void setFollowers(List<Follower> followers) {
this.followers = followers;
}
public List<Tweets> getTweets() {
return tweets;
}
public void setTweets(List<Tweets> tweets) {
Collections.reverse(tweets);
this.tweets = tweets;
}
public void setUsername(String username) {
this.username = username;
}
#Column(nullable = false)
private String username;
/*
* //email verification code
*
* #Column(length = 16) private String verificationCode;
*
* public String getVerificationCode() { return verificationCode; }
*
* public void setVerificationCode(String verificationCode) {
* this.verificationCode = verificationCode; }
*
*
* #ElementCollection(fetch = FetchType.EAGER) private Set<Role> roles = new
* HashSet<Role>();
*
*
*
* public Set<Role> getRoles() { return roles; }
*
* public void setRoles(Set<Role> roles) { this.roles = roles; }
*/
public long getId() {
return id;
}
/*
public void setId(long id) {
this.id = id;
}
*/
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isEditable() {
User loggedIn = MyTools.getSessionUser();
if (loggedIn == null) {
return false;
}
return loggedIn.getId() == id;
}
public String getUsername() {
return username;
}
}
Add a "Follow" button in JSP
<button id="follow_me">Follow</button>
Using JavaScript send the ajax call and send the user details to the controller and from the controller map it to POJO(Follower.java).
$('#follow_me').on('click',function(){
$.ajax(
url : url, // Controller URL
data : user_id, // Current User ID
follow_Flag : true,
success: function(result){
//Code for changing the view(JSP)
}});
);
});
And return the JSON to the user in the success call using below format and render it back to the JSP using JavaScript DOM Manipulation
{ userFollowFlag : true, // Current User Follow Flag
totalFollowers : 34 // Total count of followers
}
I have the following 2 entities:
#Entity
public class User implements java.io.Serializable {
private Integer iduser;
private String email;
private String password;
private Byte enabled;
private Set<Token> tokens = new HashSet<>(0);
public User() {
}
public User(String email, String password, Byte enabled/*, Set groupRights*/, Set tokens) {
this.email = email;
this.password = password;
this.enabled = enabled;
this.tokens = tokens;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "iduser", unique = true, nullable = false)
public Integer getIduser() {
return this.iduser;
}
public void setIduser(Integer iduser) {
this.iduser = iduser;
}
#Column(name = "email", unique = true, length = 45)
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "password", length = 60)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name = "enabled")
public Byte getEnabled() {
return this.enabled;
}
public void setEnabled(Byte enabled) {
this.enabled = enabled;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<Token> getTokens() {
return this.tokens;
}
public void setTokens(Set<Token> tokens) {
this.tokens = tokens;
}
}
#Entity
public class Token implements java.io.Serializable {
private String idtoken;
private User user;
private Date tokenTtl;
private String ipLock;
public Token() {
}
public Token(String idtoken) {
this.idtoken = idtoken;
}
public Token(String idtoken, User user, Date tokenTtl, String ipLock) {
this.idtoken = idtoken;
this.user = user;
this.tokenTtl = tokenTtl;
this.ipLock = ipLock;
}
#Id
#Column(name = "idtoken", unique = true, nullable = false, length = 36)
public String getIdtoken() {
return this.idtoken;
}
public void setIdtoken(String idtoken) {
this.idtoken = idtoken;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "token_ttl", length = 19)
public Date getTokenTtl() {
return this.tokenTtl;
}
public void setTokenTtl(Date tokenTtl) {
this.tokenTtl = tokenTtl;
}
#Column(name = "ip_lock", length = 45)
public String getIpLock() {
return this.ipLock;
}
public void setIpLock(String ipLock) {
this.ipLock = ipLock;
}
}
the problem is that when I select a user using this JPA-QL: select u from User u, I get a null Set related to Tokens, even though there are associated tokens for this user.
This problem arises only when I get the JPA context (EntityManager) in a Spring 4 context. If I'm doing a test, creating the EntityManager directly (using this: Persistence.createEntityManagerFactory("unit-name");), this issue is not present.
Can anybody tell me what's the cause of my issue?
You need to use in this way
private Set<Token> tokens = new HashSet<Token>(0);
Create the Getter Setter accordingley
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
public Set<Token> getTokens() {
return this.tokens;
}
public void setTokens(Set<Token>tokens) {
this.tokens = tokens;
}
The problem is related to a bug from OpenJPA.
When in OpenJPA you create a bidirectional #OneToMany relationship with FetchType.EAGER fetch type, the bug comes up by not being able to create this relation. The bug is fixed in some versions. Seems to affect versions 2.1.0, 2.2.2, 2.3.0 and 2.4.0.
References:
https://issues.apache.org/jira/browse/OPENJPA-2505
Spring Data JPA OneToMany and ManyToOne give me JpaSystemException