Hibernate doesn't save a list of authorities of a user to table as separate rows. It saves only one.

I need help to save several roles of a user to database. Using Spring Boot JPA. User can have many roles. A role belongs to one user. I tried to create three users - an admin, a user and a manager. Admin has admin role, user has user role. Manager has both - admin and user roles. I have Authority class that has a role. The problem is that for the manager hibernate creates only last role - USER. And I expected that it will have both roles. In database I see that manager has only 1 row. And it should have 2 rows. What am I doing wrong? User:
@Entity
@Table(uniqueConstraints= {@UniqueConstraint(columnNames="username")}, name = "Users")
public class User implements UserDetails{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@NonNull
private String username;
@NonNull
private String password;
@NonNull
private String email;
@OneToMany(mappedBy = "user")
private List<Authority> authorities = new ArrayList<>();
//...
@Entity
@Table(uniqueConstraints= {@UniqueConstraint(columnNames="username")}, name = "Users")
public class User implements UserDetails{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@NonNull
private String username;
@NonNull
private String password;
@NonNull
private String email;
@OneToMany(mappedBy = "user")
private List<Authority> authorities = new ArrayList<>();
//...
Authority:
@Entity
public class Authority implements GrantedAuthority {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Enumerated(EnumType.STRING)
private Role authority;
@JsonIgnore
@ManyToOne(optional = false)
private User user;
//...
@Entity
public class Authority implements GrantedAuthority {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Enumerated(EnumType.STRING)
private Role authority;
@JsonIgnore
@ManyToOne(optional = false)
private User user;
//...
21 Replies
JavaBot
JavaBot2y ago
This post has been reserved for your question.
Hey @Tomasm21! Please use /close or the Close Post button above when you're finished. Please remember to follow the help guidelines. This post will be automatically closed after 300 minutes of inactivity.
TIP: Narrow down your issue to simple and precise questions to maximize the chance that others will reply in here.
Tomasm21
Tomasm21OP2y ago
Creating users:
@PostConstruct
public void addFirstUser() throws Exception {

if (userDao.findUsersByAuthority(Role.ADMIN).size() == 0) {
List<String> adminRole = new ArrayList<>();
List<String> userRole = new ArrayList<>();
List<String> managersRoles = new ArrayList<>();
//public UserDTO(List<String> roles, String email, String username, String password)
adminRole.add("ADMIN");
UserDTO firstAdmin = new UserDTO(adminRole, "[email protected]", "[email protected]","[email protected]");

userRole.add("USER");
UserDTO firstUser = new UserDTO(userRole, "[email protected]", "[email protected]", "[email protected]");

managersRoles.add("ADMIN");
managersRoles.add("USER");
UserDTO firstManager = new UserDTO(managersRoles, "[email protected]", "[email protected]", "[email protected]");

userService.createUser(firstAdmin);
userService.createUser(firstUser);
userService.createUser(firstManager);
}
else LOG.info("There already exist users which Role is - {}", Role.ADMIN.toString());
}
@PostConstruct
public void addFirstUser() throws Exception {

if (userDao.findUsersByAuthority(Role.ADMIN).size() == 0) {
List<String> adminRole = new ArrayList<>();
List<String> userRole = new ArrayList<>();
List<String> managersRoles = new ArrayList<>();
//public UserDTO(List<String> roles, String email, String username, String password)
adminRole.add("ADMIN");
UserDTO firstAdmin = new UserDTO(adminRole, "[email protected]", "[email protected]","[email protected]");

userRole.add("USER");
UserDTO firstUser = new UserDTO(userRole, "[email protected]", "[email protected]", "[email protected]");

managersRoles.add("ADMIN");
managersRoles.add("USER");
UserDTO firstManager = new UserDTO(managersRoles, "[email protected]", "[email protected]", "[email protected]");

userService.createUser(firstAdmin);
userService.createUser(firstUser);
userService.createUser(firstManager);
}
else LOG.info("There already exist users which Role is - {}", Role.ADMIN.toString());
}
Database:
Tomasm21
Tomasm21OP2y ago
No description
Tomasm21
Tomasm21OP2y ago
Creating Users service:
@Transactional
public User createUser(UserDTO userData) {
User newUser = new User();

newUser.setEmail(userData.getEmail());
List<Authority> authority = new ArrayList<>();
Authority auth = new Authority();
for(String str : userData.getRoles()) {
auth.setAuthority(Role.valueOf(str));
authority.add(auth);
}
newUser.setAuthorities(authority);
newUser.setUsername(userData.getUsername());
newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));
User returnUser = userRepo.save(newUser);
for(Authority role : authority) {
role.setUser(returnUser);
authRepo.save(role);
}
return returnUser;
}
@Transactional
public User createUser(UserDTO userData) {
User newUser = new User();

newUser.setEmail(userData.getEmail());
List<Authority> authority = new ArrayList<>();
Authority auth = new Authority();
for(String str : userData.getRoles()) {
auth.setAuthority(Role.valueOf(str));
authority.add(auth);
}
newUser.setAuthorities(authority);
newUser.setUsername(userData.getUsername());
newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));
User returnUser = userRepo.save(newUser);
for(Authority role : authority) {
role.setUser(returnUser);
authRepo.save(role);
}
return returnUser;
}
QUESTION: Why the manager in the database has only 1 USER authority instead of two? I added 2 roles for him - admin and user. But in the DB it has only user. What I was doing wrong?
Crain
Crain2y ago
@Tomasm21 What is your database?
Tomasm21
Tomasm21OP2y ago
MariaDB HeidiSql is its Windows client
Crain
Crain2y ago
Are you working from a fresh database everytime? Like why not just seed the database with your users and such
Tomasm21
Tomasm21OP2y ago
I think the database is fresh. It runs in the memory since the boot up. I don't seed database manually I need that Spring would add users the way I defined because React.js will send data from website and spring will have to work like a charm Maybe the way I add role is not right?
User returnUser = userRepo.save(newUser);
for(Authority role : authority) {
role.setUser(returnUser);
authRepo.save(role);
}
User returnUser = userRepo.save(newUser);
for(Authority role : authority) {
role.setUser(returnUser);
authRepo.save(role);
}
Maybe this operation is immutable? single repo save can I run it in loop
Crain
Crain2y ago
You can run it in a loop
User newUser = new User();

newUser.setEmail(userData.getEmail());
newUser.setUsername(userData.getUsername());
newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));

List<Authority> authorities = new ArrayList<>();
for(String str : userData.getRoles()) {
Authority auth = new Authority();
auth.setAuthority(Role.valueOf(str));
auth.setUser(newUser);
authority.add(auth);
}
newUser.setAuthorities(authority);
return userRepo.save(newUser);
User newUser = new User();

newUser.setEmail(userData.getEmail());
newUser.setUsername(userData.getUsername());
newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));

List<Authority> authorities = new ArrayList<>();
for(String str : userData.getRoles()) {
Authority auth = new Authority();
auth.setAuthority(Role.valueOf(str));
auth.setUser(newUser);
authority.add(auth);
}
newUser.setAuthorities(authority);
return userRepo.save(newUser);
Try that? Wait I'm dumb, auth is being reused
Tomasm21
Tomasm21OP2y ago
edit
Crain
Crain2y ago
You need to put the new Authority() into the for loop, otherwise you're using the same object
Tomasm21
Tomasm21OP2y ago
mm.. ok lets see I thought we can edit the same object and just to change its property
Crain
Crain2y ago
No, you want new objects Each object represents a row in the database, so when you mutated the same object, you were changing what was going to be saved.
Tomasm21
Tomasm21OP2y ago
@Crain With your function code hibernate does not save Authorities. Only Users. But I understood idea that I need to create new Authority objects in order to add new row to the table. The service code to create new user is this:
@Transactional
public User createUser(UserDTO userData) {
User newUser = new User();

newUser.setEmail(userData.getEmail());
List<Authority> authority = new ArrayList<>();
for(String str : userData.getRoles()) {
Authority auth = new Authority();
auth.setAuthority(Role.valueOf(str));
authority.add(auth);
}
newUser.setAuthorities(authority);
newUser.setUsername(userData.getUsername());
newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));
User returnUser = userRepo.save(newUser);
for(Authority role : authority) {
role.setUser(returnUser);
authRepo.save(role);
}
return returnUser;
}
@Transactional
public User createUser(UserDTO userData) {
User newUser = new User();

newUser.setEmail(userData.getEmail());
List<Authority> authority = new ArrayList<>();
for(String str : userData.getRoles()) {
Authority auth = new Authority();
auth.setAuthority(Role.valueOf(str));
authority.add(auth);
}
newUser.setAuthorities(authority);
newUser.setUsername(userData.getUsername());
newUser.setPassword(passwordEncoder.getPasswordEncoder().encode(userData.getPassword()));
User returnUser = userRepo.save(newUser);
for(Authority role : authority) {
role.setUser(returnUser);
authRepo.save(role);
}
return returnUser;
}
First you have to save new user and get its object from database. It will have user id. then to use returned object to create his authorities and add to auth Repository. result:
Tomasm21
Tomasm21OP2y ago
No description
Tomasm21
Tomasm21OP2y ago
No description
Tomasm21
Tomasm21OP2y ago
Manager id 25.
Crain
Crain2y ago
I'm surprised my code didn't work, but I'm glad the change fixed it
Tomasm21
Tomasm21OP2y ago
Authority table now has 2 rows with constraint column values 25 Thank you.
JavaBot
JavaBot2y ago
If you are finished with your post, please close it. If you are not, please ignore this message. Note that you will not be able to send further messages here after this post have been closed but you will be able to create new posts.
JavaBot
JavaBot2y ago
Post Closed
This post has been closed by <@312509109863710732>.
Want results from more Discord servers?
Add your server