Spring (Hibernate) - incomplete serialization result / many-to-many - spring

Rest Application / Spring MVC - 3 entities: User, AccessRole, AccessPermision.
Each user has only one role, each role has one or more privileges.
The problem occurs during serialization of users with the same role.
In such case, the JSON serialization result, contains permissions only for the first user.
User Entity
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import socialcreek.access.model.AccessRole;
import socialcreek.user.views.UserViews;
import javax.persistence.*;
import java.util.Set;
#Entity
#Table(name = "users")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class User {
/**-----------------------------------------------------
* Constructor
-------------------------------------------------------*/
public User(){ }
public User(String username, String password, AccessRole accessRole) {
this.username = username;
this.password = password;
this.userAccessRole = accessRole;
}
/**-----------------------------------------------------
* Entity Properties
-------------------------------------------------------*/
#Column()
#Id
#JsonView(UserViews.BasicView.class)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonView(UserViews.BasicView.class)
private String username;
private String password;
#JsonView(UserViews.BasicView.class)
#ManyToMany(mappedBy = "users",fetch=FetchType.EAGER)
private Set<UsersGroup> usersGroups;
#ManyToOne(targetEntity = AccessRole.class, optional = false,fetch = FetchType.EAGER, cascade=CascadeType.MERGE)
#JoinColumn(name = "user_role")
#JsonView(UserViews.BasicView.class)
private AccessRole userAccessRole;
/**-----------------------------------------------------
* Setters & Getters
-------------------------------------------------------*/
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 Set<UsersGroup> getUsersGroups() {
return usersGroups;
}
public void setUsersGroups(Set<UsersGroup> usersGroups) {
this.usersGroups = usersGroups;
}
public AccessRole getUserAccessRole() {
return userAccessRole;
}
public void setUserAccessRole(AccessRole userAccessRole) {
this.userAccessRole = userAccessRole;
}
}
AccessRole Entity
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import socialcreek.user.views.UserViews;
import javax.persistence.*;
import java.util.Set;
#Entity
#Table(name = "access_role")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class AccessRole {
/**-----------------------------------------------------
* Entity Properties
-------------------------------------------------------*/
#Id
#JsonView(UserViews.BasicView.class)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonView(UserViews.BasicView.class)
private String roleName;
#JsonView(UserViews.BasicView.class)
#ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
#JoinTable(name = "access_role_permissions")
private Set<AccessPermission> accessPermissions;
/**-----------------------------------------------------
* Setters & Getters
-------------------------------------------------------*/
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getRoleName() {
return roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
public Set<AccessPermission> getAccessPermissions() {
return accessPermissions;
}
public void setAccessPermissions(Set<AccessPermission> accessPermissions) {
this.accessPermissions = accessPermissions;
}
}
AccessPermission Entity
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import socialcreek.user.views.UserViews;
import javax.persistence.*;
#Entity
#Table(name = "access_permission")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,property = "id")
public class AccessPermission {
/**-----------------------------------------------------
* Entity Properties
-------------------------------------------------------*/
#Id
#JsonView(UserViews.BasicView.class)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#JsonView(UserViews.BasicView.class)
private String permissionName;
/**-----------------------------------------------------
* Setters & Getters
-------------------------------------------------------*/
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPermissionName() {
return permissionName;
}
public void setPermissionName(String permissionName) {
this.permissionName = permissionName;
}
}
Serialization Result:
[ { "id":70, "username":"admin", "usersGroups":[], "userAccessRole":{
"id":68, "roleName":"ROLE_ADMIN", "accessPermissions":[
{
"id":69,
"permissionName":"FULL_ACCESS"
}]} },
{ "id":71, "username":"admin2", "usersGroups":[], "userAccessRole":68}
]
Please, have a look at accessRole and accessPermision information - it's complete only for the user:admin. In case of user:admin2 there is only information about accessRoleId ( no information about roleName, accessPermision)
It happens only when both users have the same accessRole. If I change accessRole of user:admin2 to another role - everythnink will be ok.

I found the similar issue with the correct answer (https://stackoverflow.com/a/27117097/4694022).
The problem is caused by #JsonIdentityInfo. After I removed it - it works ...now I need to find the solution to handle serialization for recursive structure but it's another story ...

Related

Spring Boot Rest API Issues

I'm trying to implement a Spring Boot Rest API using Spring Data Jdbc with H2 Database.
This is a microservice, and I'm trying to send a POST request to the microservice from an angular app. I know my POST is working correctly from Angular. Inside of microservice, I am trying to save the POST request to a local H2 database.
This should be relatively straight forward based on documentation I've read online, but I am getting error messages. Any help would be greatly appreciated. Here are the files I have setup inside my spring boot microservice (titled 'order'):
OrderController.java:
package com.clothingfly.order;
import java.util.ListIterator;
import org.springframework.web.client.RestTemplate;
import com.clothingfly.order.Model.Item;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.clothingfly.order.Model.Order;
#RestController
#CrossOrigin(origins = "http://localhost:4200")
public class OrderController {
#Autowired
TempOrderRepository orderRepository;
#PostMapping("/order")
public Order postOrder(#RequestBody Order order) {
Order _order = orderRepository.save(new Order(order.getId(), order.getAddress(), order.getPayment(), order.getItems()));
return _order;
}
}
TempOrderRepository.java:
package com.clothingfly.order;
import org.springframework.data.jpa.repository.JpaRepository;
import com.clothingfly.order.Model.Order;
public interface TempOrderRepository extends JpaRepository<Order, Long>{
}
OrderApplication.java:
package com.clothingfly.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
And I have a model named Order.java:
package com.clothingfly.order.Model;
import java.util.List;
import javax.persistence.*;
import org.springframework.data.annotation.Id;
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "Address")
private Address address;
#Column(name = "Payment")
private PaymentInfo payment;
#Column(name = "Items")
private List<Item> items;
#Column(name = "Error")
private String error;
public Order() {
}
public Order(long id, Address address, PaymentInfo payment, List<Item> items){
this.id = id;
this.address = address;
this.payment = payment;
this.items = items;
this.error = "";
}
public long getId() {
return id;
}
public Address getAddress() {
return address;
}
public PaymentInfo getPayment() {
return payment;
}
public List<Item> getItems() {
return items;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}
The Order model takes in three other models:
Item.java:
package com.clothingfly.order.Model;
import javax.persistence.*;
#Entity
#Table(name = "items")
public class Item {
#Id
#GeneratedValue
#Column(name = "id")
private long id;
#Column(name = "name")
private String name;
#Column(name = "price")
private float price;
#Column(name = "imageUrl")
private String imageUrl;
#Column(name = "quantity")
private long quantity;
#Column(name = "inventory")
private long inventory;
public long getId() {
return id;
}
public String getName() {
return name;
}
public float getPrice() {
return price;
}
public long getQuantity() {
return quantity;
}
public long getInventory() {
return inventory;
}
public String getImageUrl(){
return imageUrl;
}
public void setInventory(long inventory) {
this.inventory = inventory;
}
public void setName(String name) {
this.name = name;
}
public void setPrice(float price) {
this.price = price;
}
public void setQuantity(long quantity) {
this.quantity = quantity;
}
public Item(long id, String name, float price, long quantity, long inventory, String imageUrl) {
this.id = id;
this.name = name;
this.price = price;
this.quantity = quantity;
this.inventory = inventory;
this.imageUrl = imageUrl;
}
public Item() {
}
}
Address.java:
package com.clothingfly.order.Model;
import javax.persistence.*;
#Entity
#Table(name = "addresses")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "address")
private String address;
#Column(name = "country")
private String country;
#Column(name = "apartmentNo")
private String apartmentNo;
#Column(name = "state")
private String state;
#Column(name = "city")
private String city;
#Column(name = "zipcode")
private String zipcode;
public Address() {
}
public Address(String firstName, String lastName, String address, String country, String apartmentNo, String state,
String city, String zipcode) {
this.firstName = firstName;
this.lastName = lastName;
this.address = address;
this.country = country;
this.apartmentNo = apartmentNo;
this.state = state;
this.city = city;
this.zipcode = zipcode;
}
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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getApartmentNo() {
return apartmentNo;
}
public void setApartmentNo(String apartmentNo) {
this.apartmentNo = apartmentNo;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
}
PaymentInfo.java:
package com.clothingfly.order.Model;
import javax.persistence.*;
#Entity
#Table(name = "payments")
public class PaymentInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "cardHolder")
private String cardHolder;
#Column(name = "cardNumber")
private String cardNumber;
#Column(name = "expirationDate")
private String expirationDate;
#Column(name = "cvv")
private String cvv;
public PaymentInfo(String cardHolder, String cardNumber, String expirationDate, String cvv) {
this.cardHolder = cardHolder;
this.cardNumber = cardNumber;
this.expirationDate = expirationDate;
this.cvv = cvv;
}
public String getCardHolder() {
return cardHolder;
}
public void setCardHolder(String cardHolder) {
this.cardHolder = cardHolder;
}
public String getCardNumber() {
return cardNumber;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public String getExpirationDate() {
return expirationDate;
}
public void setExpirationDate(String expirationDate) {
this.expirationDate = expirationDate;
}
public String getCvv() {
return cvv;
}
public void setCvv(String cvv) {
this.cvv = cvv;
}
}
I'm getting the following error when trying to run microservice:
Unable to build Hibernate SessionFactory; nested exception is org.hibernate.MappingException: Could not determine type for: com.clothingfly.order.Model.Address, at table: orders, for columns: [org.hibernate.mapping.Column(address)]
How would I go about fixing this?
I want to be able to display all of my models inside a table.
I tried changing Address model so that it only returns a string of the city, but that seemed to cause more issues than anything.
Note, one to one will always cause you an issue, always better to implement many to one and one to many. and add it to both entities you are mapping. It will do the same job with no errors.
First, create packages, and don't place everything in one package.
create
package com.clothingfly.repo or com.clothingfly.order.repo
package com.clothingfly.controller or com.clothingfly.order.controller
Secondly, add the annotation #Repository to your repository interface
package com.clothingfly.repo;
import org.springframework.data.jpa.repository.JpaRepository;
import com.clothingfly.order.Model.Order;
#Repository
public interface TempOrderRepository extends JpaRepository<Order, Long>{
}
Thirdly, add the annotation #EnableJpaRepositories(basePackages = "com.clothingfly.repo") to your main application class.
package com.clothingfly.order;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
#EnableJpaRepositories(basePackages = "com.clothingfly.repo")
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
}
Lastly, this will not work correctly. Not sure what you are doing here.
#Column(name = "Address")
private Address address;
Try this:
add this in your address entity
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name="order_id", nullable = false)// add this column
// order_id in your Address database not the entity
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Order order;
Then, add this to your Order class.
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="order")
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
List<Address> address = new ArrayList<Address>(); // I use list cause sometimes it throws an error
// try to simply use this, if it throws expection then use the list
//private Address address;
Your Order constructor should be like:
public Order(long id, List<Address> address ...etc
Or simply
public Order(long id, Address address ...etc
Do this for all your mapped entities and don't forget to add setters and getters for all fields.
you have to tell hibernate that the Address object is coming from another table and how to join those tables, since your orders table most likely does not have a column which contains the hole address but the the address id/ primary key of the address as foreign key.
this is possible, depending if you have 1:1, 1:n, n:1 or n:m relations with the corresponding #OneToOne, #OneToMany, #ManyToOne and #ManyToMany annotations.
for your example it could be something like
#OneToOne
#JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;

Relationship CRUD API Spring Boot

I am creating a crud api with a many to many relationship betwen role and user. When i make a Get HTTP Request, i get the mesage below but When i delete all relationship and make findall on single table, it works percfecttly. Where do you think the problem is?
Error Message in postman
{
"timestamp": "2021-07-10T04:28:24.877+0000",
"status": 500,
"error": "Internal Server Error",
"message": "JSON mapping problem: java.util.ArrayList[0]->com.notyfyd.entity.User[\"roles\"]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: com.notyfyd.entity.User.roles, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.notyfyd.entity.User[\"roles\"])",
"path": "/user/all"
}
Role Entity
package com.notyfyd.entity;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "t_role")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#ManyToMany(targetEntity = User.class, mappedBy = "roles", cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH})
private List<User> users;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public List<User> getUsers() {
return users;
}
public void setUsers(List<User> users) {
this.users = users;
}
}
User Entity
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import javax.persistence.*;
import java.util.List;
#Entity
#Table(name = "t_user")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private String mobile;
#Column(unique = true)
private String email;
#ManyToMany(targetEntity = Role.class, cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH} )
#JoinTable(
name="t_user_roles",
joinColumns=
#JoinColumn( name="user_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="role_id", referencedColumnName="id"))
private List<Role> roles;
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
public Long getId() {
return id;
}
public void setId(Long 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 getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
here is the log error on MSSQL Server
2021-07-10 11:20:59.333 WARN 3124 --- [nio-6120-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: failed to lazily initialize a collection of role: fdsa.edu.PNUFDSA.Model.AnneeAcademique.paiements, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: fdsa.edu.PNUFDSA.Model.AnneeAcademique.paiements, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->fdsa.edu.PNUFDSA.Model.AnneeAcademique["paiements"])]
the Entity is:
* "Visual Paradigm: DO NOT MODIFY THIS FILE!"
*
* This is an automatic generated file. It will be regenerated every time
* you generate persistence class.
*
* Modifying its content may cause the program not work, or your work may lost.
*/
/**
* Licensee:
* License Type: Evaluation
*/
package fdsa.edu.PNUFDSA.Model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
#Entity
#Data
//#org.hibernate.annotations.Proxy(lazy=false)
#Table(name="AnneeAcademique")
public class AnneeAcademique implements Serializable {
public AnneeAcademique() {
}
#Column(name="ID", nullable=false, length=10)
#Id
#GeneratedValue(generator="PNU_ANNEEACADEMIQUE_ID_GENERATOR")
#org.hibernate.annotations.GenericGenerator(name="PNU_ANNEEACADEMIQUE_ID_GENERATOR", strategy="native")
private int id;
#Column(name="Debut", nullable=true)
#Temporal(TemporalType.DATE)
private java.util.Date debut;
#Column(name="Fin", nullable=true)
#Temporal(TemporalType.DATE)
private java.util.Date fin;
#JsonIgnore
#ManyToMany(mappedBy="anneeAcademiques", targetEntity=fdsa.edu.PNUFDSA.Model.Cours.class)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
#org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.TRUE)
private java.util.Set cours = new java.util.HashSet();
#JsonIgnore
#OneToMany(mappedBy="anneeAcademique", targetEntity=fdsa.edu.PNUFDSA.Model.Paiement.class)
#org.hibernate.annotations.Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.LOCK})
#org.hibernate.annotations.LazyCollection(org.hibernate.annotations.LazyCollectionOption.TRUE)
private List paiements = new ArrayList();
private void setId(int value) {
this.id = value;
}
public int getId() {
return id;
}
public int getORMID() {
return getId();
}
public void setDebut(java.util.Date value) {
this.debut = value;
}
public java.util.Date getDebut() {
return debut;
}
public void setFin(java.util.Date value) {
this.fin = value;
}
public java.util.Date getFin() {
return fin;
}
public void setCours(java.util.Set value) {
this.cours = value;
}
public java.util.Set getCours() {
return cours;
}
public void setPaiements(List value) {
this.paiements = value;
}
public List getPaiements() {
return paiements;
}
public String toString() {
return String.valueOf(getId());
}
}
Are you returning that entity directly as json. Can add #JsonIgnore on below field.
#JsonIgnore
private List<Role> roles;
You can set fetch type to FetchType.EAGER on your many to many relations in your entities.
Try this and let me know what happened.

Targeting unmapped class error in Spring boot app

I work on basic exemplary app that is about #OneToMany & ManyToOne annotation. I define mapping between two classes, apparently there is no error but on running app it gives me an error : Use of #OneToMany or #ManyToMany targeting an unmapped class: com.orchard.orchard.model.AppUser.userRole[ com.orchard.orchard.model.UserRole]
I'm failed to understand where does problem lies as mapping also describe in AppUser. I'd be grateful for the help.
Classes are as follows:
AppUser.java
package com.orchard.orchard.model;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
#Entity
public class AppUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(updatable = false, nullable = false)
private Integer id;
private String name;
#Column(unique = true)
private String username;
private String password;
private String email;
#Column(columnDefinition = "text")
private String bio;
private Date createdDate;
#OneToMany(mappedBy = "appUser", cascade = CascadeType.ALL, fetch =
FetchType.EAGER)
private Set<UserRole> userRole = new HashSet<>();
public AppUser() {
}
public AppUser(Integer id, String name, String username, String
password, String email, String bio,
Date createdDate, Set<UserRole> userRoles) {
this.id = id;
this.name = name;
this.username = username;
this.password = password;
this.email = email;
this.bio = bio;
this.createdDate = createdDate;
this.userRole = userRoles;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getBio() {
return bio;
}
public void setBio(String bio) {
this.bio = bio;
}
public Date getCreatedDate() {
return createdDate;
}
public void setCreatedDate(Date createdDate) {
this.createdDate = createdDate;
}
public Set<UserRole> getUserRoles() {
return userRole;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRole = userRoles;
}
}
UserRole.java
package com.orchard.orchard.model;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.fasterxml.jackson.annotation.JsonIgnore;
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long userRoleId;
#ManyToOne
#JoinColumn(name = "user_id")
#JsonIgnore
private AppUser appUser;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "role_id")
private Role role;
public UserRole() {
}
public UserRole(long userRoleId, AppUser appUser, Role role) {
this.userRoleId = userRoleId;
this.appUser = appUser;
this.role = role;
}
public long getUserRoleId() {
return userRoleId;
}
public void setUserRoleId(long userRoleId) {
this.userRoleId = userRoleId;
}
public AppUser getAppUser() {
return appUser;
}
public void setAppUser(AppUser appUser) {
this.appUser = appUser;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
}
You forgot to add #Entity annotation to your UserRole class
#Entity
public class UserRole {
}

problem with saving data in many-to-many intermediate table spring boot

following are my entity
package bt.gov.dit.inventoryservice.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
//import org.hibernate.mapping.Set;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "items")
public class Items implements Serializable {
private Long Id;
#Column(name = "item_name")
private String itemName;
// #ManyToOne(fetch = FetchType.LAZY)
// #JoinColumn(name = "categories_id",nullable = false, referencedColumnName = "id")
private Categories categories;
private Stores stores;
//#Temporal(TemporalType.TIMESTAMP)
#Column(name = "insert_date")
private Date insertDate = new Date();
// #Temporal(TemporalType.TIMESTAMP)
#Column(name = "update_date")
private Date updateDate = new Date();
private Set<Logs> logs = new HashSet<Logs>() ;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return Id;
}
public void setId(Long id) {
Id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "categories_id", nullable = false, referencedColumnName = "id")
public Categories getCategories() {
return categories;
}
public void setCategories(Categories categories) {
this.categories = categories;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "stores_id", nullable = false, referencedColumnName = "id")
public Stores getStores() {
return stores;
}
public void setStores(Stores stores) {
this.stores = stores;
}
public Date getInsertDate() {
return insertDate;
}
public void setInsertDate(Date insertDate) {
this.insertDate = insertDate;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "items_logs", joinColumns = #JoinColumn(name = "items_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "logs_id",referencedColumnName = "id") )
public Set<Logs> getLogs() {
return logs;
}
public void setLogs(Set<Logs> logs) {
this.logs = logs;
}
}
package bt.gov.dit.inventoryservice.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "logs")
public class Logs {
private Long id;
#Column(name = "cadet_id")
private Long cadetId;
private Set<Items> items = new HashSet<Items>() ;
#Column(name = "borrowed_date")
//#Temporal(TemporalType.TIMESTAMP)
private Date borrowedDate = new Date();
private String status;
private String comments;
#Id
#GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getCadetId() {
return cadetId;
}
public void setCadetId(Long cadetId) {
this.cadetId = cadetId;
}
public Date getBorrowedDate() {
return borrowedDate;
}
public void setBorrowedDate(Date borrowedDate) {
this.borrowedDate = borrowedDate;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
#ManyToMany(fetch = FetchType.LAZY,mappedBy = "logs")
public Set<Items> getItems() {
return items;
}
public void setItems(Set<Items> items) {
this.items = items;
}
}
I have many to many relationship between them. Due to that there is an intermediate table created with field item_id and log_id. Now I don't know how to save data in that table. I can save items and i can save log. But I have problem with saving the many-to-many relationship between them?

Hibernate connecting table unique on columns problem

I have problem with hibernate because he creates connecting table (I don't know why will be nice if can tell me where and why), and what is worst he using unique on columns and i cant add more then one user with the same role.
Whole project: https://github.com/dextep/sms/tree/master/src/main/java/pl/popiel/sms
Database look
User.class
package pl.popiel.sms.model.user;
import org.hibernate.validator.constraints.UniqueElements;
import javax.persistence.*;
import javax.validation.constraints.Email;
import java.util.Set;
#Entity
#Table(name="sms_users")
#SequenceGenerator(name = "sms_users_seq", sequenceName = "sms_users_seq", allocationSize = 1)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sms_users_seq")
private long id;
#Email
private String email;
private String password;
private String firstName;
private String lastName;
#Column(name="mobile_nr")
private String mobileNumber;
#ElementCollection(targetClass=Role.class)
private Set<Role> roles;
public String getFullName() {
return firstName != null ? firstName.concat(" ").concat(lastName) : "";
}
public User() {
}
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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 getMobileNumber() {
return mobileNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
Role.class
package pl.popiel.sms.model.user;
import org.hibernate.validator.constraints.UniqueElements;
import org.springframework.stereotype.Indexed;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="sms_roles")
#SequenceGenerator(name = "sms_roles_seq", sequenceName = "sms_roles_seq", allocationSize = 1)
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sms_roles_seq")
private long id;
private String role;
public Role() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
I didn't notice that I miss the #ManyToMany annotation at 'roles' in User class.
Solve:
#ManyToMany
private Set<Role> roles;

Resources