Can't assign a default user_role="ROLE_USER" with Hibernate - spring

I have a user model and I am triyng to set a default role="role_user" in my postgreSQL database when a user register. My User model is:
#Entity
#Table(name = "users")
public class User {
#NotEmpty(message = "Campul nu poate fi lasat gol")
#Size(min = 4, max = 16,message = "Dimensiunea trebuie sa fie intre 4 si 16 caractere")
private String firstName;
#NotEmpty(message = "Campul nu poate fi lasat gol")
#Size(min = 4, max = 16,message = "Dimensiunea trebuie sa fie intre 4 si 16 caractere")
private String lastName;
#Id
#NotEmpty(message = "Campul nu poate fi gol")
#Email(message = "Email-ul trebuie sa fie valid")
private String email;
#NotEmpty(message = "Campul nu poate fi gol")
#Size(min = 4, max = 60, message = "Parola trebuie sa contina minim 4 caractere")
private String password;
private String role;
private boolean enabled = true;
public User() {};
public User(String firstName, String lastName, String email, String password,String role) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
this.role = role;
}
How can I solve the problem. I saw another posts on stackoverflow but I don't understand, I'm quite new in Spring

You can just initialize your field with the default value.
private String role = "role_user";
public User(String firstName, String lastName, String email, String password,String role) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
if(role != null) { this.role = role; }; // if you need to keep the default value
}

Related

Spring boot table to show list of pets by owner id

I'm making a small school project Spring Boot web application. Right now I have made CRUD for Owners table in the database, what I'm trying to do next is when I click button "pets" I want to be able to show only those pets that has the same "owner_id". I guess I should receive "owner_id" from the button that was pressed. How can I make that it works the way it should work? Now when I press button "pets" it shows all list of the pets.
Owner class:
#Entity
#Table(name = "owners")
public class Owner {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "first_name", nullable = false)
private String firstName;
#Column(name = "last_name", nullable = false)
private String lastName;
#Column(name = "email", nullable = false)
private String email;
#OneToMany(targetEntity = Pet.class,cascade = CascadeType.ALL)
#JoinColumn(name = "owner_id", referencedColumnName = "id")
private List<Pet> pets;
public Owner() {
}
public Owner(String firstName, String lastName, String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
}
Pet class:
#Table(name = "pets")
public class Pet {
#Id
private Long id;
private String name;
private String breed;
private int age;
private double weight;
public Pet() {
}
public Pet(String name, String breed, int age, double weight) {
super();
this.name = name;
this.breed = breed;
this.age = age;
this.weight = weight;
}
}
Controller method for list of pets:
#GetMapping("/owner_pets")
public String getAllPetsByOwnerId(Model model) {
model.addAttribute("pets", petService.getAllPetsByOwnerId());
return "owner_pets";
}
Here is the code written so far but it only shows list of all pets
I saw your service method for PerService. I do not see any ownerId being passed to findByOwnerId method. That might be the reason why you are getting all pets in response. What you should ideally do is
package com.veterinary.Veterinary_system.service;
import java.util.List;
import com.veterinary.Veterinary_system.entity.Pet;
public interface PetService {
//Repository declaration
List < Pet > findByOwnerId(Long ownerId){
return petRepository.findByOwnerId(ownerId);
}
Pet savePet(Pet pet);
}

Can't get products by userId from repository

I have 2 tables. One of them called 'products'
#Data
#Entity
#Table(name = "products")
#NoArgsConstructor
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(length = 100)
#NotBlank(message = "Name must be written")
private String name;
#Column(length = 200)
#NotBlank(message = "Provide image (link in this case) of your product")
private String image;
#PositiveOrZero
private int amount;
#Column(length = 250)
#NotBlank(message = "description must be written")
#Size(min = 10, max = 250, message = "description is too long or empty")
private String description;
#PositiveOrZero
private float price;
#ManyToOne
#JoinColumn(name = "type_id")
private ProductType productType;
public Product(#NotBlank String name, String image, int amount, #NotBlank String description,
#PositiveOrZero float price, ProductType productType) {
this.name = name;
this.image = image;
this.amount = amount;
this.description = description;
this.price = price;
this.productType = productType;
}
}
another table is 'users'
#Data
#Entity
#NoArgsConstructor
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(length = 50)
#Size(min = 2, max = 30, message = "enter appropriate amount of letters, min 2")
private String username;
#Column(length = 100)
#Email(message = "Enter a valid email")
#NotBlank(message = "email should have a value")
private String email;
#Column(length = 50)
#NotBlank(message = "password should have a value")
#Size(min = 6, message = "password should at least consist of 6 characters")
private String password;
private boolean enabled;
private String role;
public User(#Size(min = 2, max = 30, message = "enter appropriate amount of letters, min 2")
String username,
#Email(message = "Enter a valid email")
#NotBlank(message = "email should have a value") String email,
#NotBlank(message = "password should have a value")
#Size(min = 6, message = "password should at least consist of 6 characters")
String password, boolean enabled, String role) {
this.username = username;
this.email = email;
this.password = password;
this.enabled = enabled;
this.role = role;
}
}
and also table that include both 'product_user' (many to many relationship)
it looks like this
#Data
#Entity
#Table(name = "product_user")
#AllArgsConstructor
#NoArgsConstructor
public class ProdAndUser{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer id;
#ManyToOne
#JoinColumn(name = "product_id")
Product product;
#ManyToOne
#JoinColumn(name = "user_id")
User user;
public ProdAndUser(Product product, User user) {
this.product = product;
this.user = user;
}
}
then I tried to get them from prodAndUser repository by UserId or by User as obj:
#Repository
public interface ProdAndUserRepository extends JpaRepository<ProdAndUser, Integer> {
List<ProdAndUser> getProdAndUsersByUserId(Integer id);
List<ProdAndUser> getAllByUser(User user);
}
my controller looks like this:
#ResponseBody
#GetMapping("/findByUsr/{user}")
public List<ProdAndUser> getByUser(#PathVariable User user){
return prodAndUserRepository.getAllByUser(user);
}
error:
{
"timestamp": "2022-02-12T05:52:53.165+00:00",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/Cart/findByUsr"
}
I have tried to find them all by .findAll() and it worked fine. Also another tables work fine on their own
Look at the error it says (404) means something is not right with the path.
The path on the error does not contain user_id.

How to get rid of "Could not write JSON: failed to lazily initialize a collection of role" if i have #Transactional and JOIN FETCH?

I have Rest #GetMapping method :
#GetMapping(value = "/getAdmin",produces = "application/json")
public List<Users> listOfUsers(){
return userService.findAllUsers();
}
findAllUsers function looks like :
#Override
#Transactional
public List<Users> findAllUsers() {
String hqlRequest = "from Users U JOIN FETCH U.roles";
Query query = sessionFactory.getCurrentSession().createQuery(hqlRequest);
}
That is, JOIN FETCH works fine if i just call:
List<Users> users = userService.findAllUsers();
System.out.println(users);
but when a request is sent to the listOfUsers method, I get an error:
Could not write JSON: failed to lazily initialize a collection of role
I have read solutions to this problem and there it is advised to add the #Transaction annotation or use joint fetch in the request, but I have both, but I still get an error.Can someone explain how to get rid of this error and?
Users
package com.example.securityWithHibernate.Model;
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import java.util.Set;
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
#Length(min = 5, message = "*Your user name must have at least 5 characters")
#NotEmpty(message = "*Please provide a user name")
private String name;
#Column(name = "first_name")
#NotEmpty(message = "*Please provide your name")
private String firstName;
#Column(name = "last_name")
#NotEmpty(message = "*Please provide your last name")
private String lastName;
#Column(name = "email")
#Email(message = "*Please provide a valid Email")
#NotEmpty(message = "*Please provide an email")
private String email;
#Column(name = "user_password")
#Length(min = 5, message = "*Your password must have at least 5 characters")
#NotEmpty(message = "*Please provide your password")
private String userPassword;
public Set<Roles> getRoles() {
return roles;
}
public void setRoles(Set<Roles> roles) {
this.roles = roles;
}
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "user_roles",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Roles> roles;
public Users(Long id, String name, String firstName, String lastName, String email, String userPassword) {
this.id = id;
this.name = name;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.userPassword = userPassword;
}
/*public Users( String name, String firstName, String lastName, String email, String userPassword) {
this.name = name;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.userPassword = userPassword;
}*/
public Users() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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 getUserPassword() {
return userPassword;
}
public void setUserPassword(String userPassword) {
this.userPassword = userPassword;
}
#Override
public String toString() {
return "Users{" +
"id=" + id +
", name='" + name + '\'' +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
", email='" + email + '\'' +
", userPassword='" + userPassword + '\'' +
", roles=" + roles +
'}';
}
}
Roles
package com.example.securityWithHibernate.Model;
import javax.persistence.*;
import java.util.Set;
#Entity
#Table(name = "roles")
public class Roles {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
public Roles(Long id, String role) {
this.id = id;
this.role = role;
}
public Roles() {
}
#Column(name = "role_name")
private String role;
#ManyToMany(mappedBy = "roles")
private Set<Users> users;
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;
}
public Set<Users> getUsers() {
return users;
}
public void setUsers(Set<Users> users) {
this.users = users;
}
#Override
public String toString() {
return "Roles{" +
"id=" + id +
", role='" + role + '\'' +
'}';
}
}

Null Foreign Key (Springboot, Hibernate, Postman)

I am using Springboot with Hibernate and I would like to save a new “post” using a POST request to my database. One thing that I would like to highlight is that I am using the dependency “spring-boot-starter-data-rest”.
Schema of the database (MySQL):
Class User:
#Entity
#Table(name="user")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable = false)
public int id;
#OneToMany(mappedBy = "user_id_fk")
public Set<Post> posts;
#Column(name="email")
private String email;
#Column(name="username")
private String username;
#Column(name="password")
private String password;
#Column(name="first_name")
private String firstName;
#Column(name="last_name")
private String lastName;
#Column(name="create_time")
protected Date createTime;
#Column(name="type")
private String accountType;
public User() {
this.createTime = new java.util.Date();
}
public User(String email, String username, String password, String firstName, String lastName, Date createTime, String accountType) {
this.email = email;
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.createTime = createTime;
this.accountType = accountType;
this.createTime = new java.util.Date();
}
public User(int id, String email, String username, String password, String firstName, String lastName, Date createTime, String accountType) {
this.id = id;
this.email = email;
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
this.createTime = createTime;
this.accountType = accountType;
this.createTime = new java.util.Date();
}
Plus the Getters & Setters & toString().
Class Post:
#Entity
#Table(name="post")
public class Post implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
public int id;
#ManyToOne(optional = false)
#JoinColumn(name = "user_id_fk", nullable = false)
public User user_id_fk;
#Column(name="comment")
private String comment;
#Column(name="likes")
private int likes;
#Column(name="dislike")
private int dislike;
#Column(name="create_time")
protected Date createTime;
public Post() {
this.createTime = new java.util.Date();
}
public Post(String comment, int likes, int dislike, User user_id_fk) {
this.user_id_fk = user_id_fk;
this.comment = comment;
this.likes = likes;
this.dislike = dislike;
this.createTime = new java.util.Date();
}
public Post(int id, User user_id_fk, String comment, int likes, int dislike) {
this.id = id;
this.user_id_fk = user_id_fk;
this.comment = comment;
this.likes = likes;
this.dislike = dislike;
this.createTime = new java.util.Date();
}
Plus the Getters & Setters & toString().
Post request (I'm using Postman to send the request):
{
"comment" : "This is a comment",
"likes" : 123,
"dislike" : 1,
"user_id_fk" :
[
{
"id" : 1
}
]
}
In the request at the "user_id_fk" I tried with [ {"id" : 1 } ] and with { "id" : 1 } but the result was the same.
Issue:
When I am executing exactly the same code from my controller everything works are excepted. Bear in mind that I am using the dependency “spring-boot-starter-data-rest”.
Also, when I am executing the code without the “optional = false” and “nullable = false” is inserting the data into the database but the “user_id_fk” is null :(.
The error that I am getting:
not-null property references a null or transient value : com.citizen.citizen.entity.Post.user_id_fk;
nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value : com.citizen.citizen.entity.Post.user_id_fk]
That means that the foreign key ("user_id_fk") is null but should not be null.
Any help will be greatly appreciated.
I just remove the dependency "spring-boot-starter-data-rest" and I solved the issue by creating my custom rest and everything works. Kisses!
According to this article, you should make user_id_fk nullable and then:
Send POST to create User
Send second POST to create Post
Send PUT to create a relation between the two.
This article states the same.
And the documentation only mentions handling associations via association links.

Springboot: What is the best way to search for a List of an entity using more than one of its characteristics

I am developing a web application in spring-boot, where a user can search for users using a search field. The users being searched (which depends on the value typed into the input field) will be queried according to their username, first name and last-name. This is my UserModel :
#Component
#Entity
#Table(name = "Users")
public class User extends DefaultEntity {
#Column(name = "FirstName")
#NotNull(message = "Enter a FirstName")
private String firstName;
#Column(name = "LastName")
#NotBlank(message = "Enter a LastName")
private String lastName;
#Column(unique = true,name = "UserName")
#NotBlank(message = "Enter a UserName")
private String userName;
#Column(unique = true, name = "Email")
#NotBlank(message = "Please enter an Email address")
#Email(message = "Enter a valid Email")
private String email;
#Column(name = "Password")
#NotBlank(message = "Enter a Password")
private String password;
#Enumerated(EnumType.STRING)
#Column(name = "Gender")
private Gender gender;
#Column(name = "Address")
#NotBlank(message = "Please enter your Home Address")
private String address;
#Column(name = "Country")
#NotBlank(message = "Please enter your Country")
private String country;
#Column(name = "Picture")
private String picture;
#Column(unique = true, name = "PhoneNumber") //make this accept only numbers
private String phoneNumber;
#Column(name = "Bio")
private String bio;
#Enumerated(EnumType.STRING)
#Column(name = "OnlineStatus")
private OnlineStatus onlineStatus;
#Enumerated(EnumType.STRING)
#Column(name = "UserType")
private UserType userType;
#Column(name = "Money")
private double money;
//#MapsId()
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "playerstats")
private PlayerStats playerStats;
//columnDefinition = "tinyint default false"
#Column(name = "locked",columnDefinition = "BOOL default false")
private Boolean locked;
#Transient
private MultipartFile file;
public String getFirstName() {
return firstName;
}
public User setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public String getLastName() {
return lastName;
}
public User setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public String getUserName() {
return userName;
}
public User setUserName(String userName) {
this.userName = userName;
return this;
}
public String getEmail() {
return email;
}
public User setEmail(String email) {
this.email = email;
return this;
}
public String getPassword() {
return password;
}
public User setPassword(String password) {
this.password = password;
return this;
}
public Enum.Gender getGender() {
return gender;
}
public User setGender(Enum.Gender gender) {
this.gender = gender;
return this;
}
public String getAddress() {
return address;
}
public User setAddress(String address) {
this.address = address;
return this;
}
public String getCountry() {
return country;
}
public User setCountry(String country) {
this.country = country;
return this;
}
public String getPicture() {
return picture;
}
public User setPicture(String picture) {
this.picture = picture;
return this;
}
public String getBio() {
return bio;
}
public User setBio(String bio) {
this.bio = bio;
return this;
}
public Enum.OnlineStatus getOnlineStatus() {
return onlineStatus;
}
public User setOnlineStatus(Enum.OnlineStatus onlineStatus) {
this.onlineStatus = onlineStatus;
return this;
}
public Enum.UserType getUserType() {
return userType;
}
public User setUserType(Enum.UserType userType) {
this.userType = userType;
return this;
}
public double getMoney() {
return money;
}
public User setMoney(double money) {
this.money = money;
return this;
}
public String getPhoneNumber() {
return phoneNumber;
}
public User setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public MultipartFile getFile() {
return file;
}
public User setFile(MultipartFile file) {
this.file = file;
return this;
}
public PlayerStats getPlayerStats() {
return playerStats;
}
public User setPlayerStats(PlayerStats playerStats) {
this.playerStats = playerStats;
return this;
}
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
}
this is my method for querying the usermodel in my UserRepository :
#Repository
public interface UserRepository extends JpaRepository<User,Long> {
Page<User> findUsersByUserNameContainingOrFirstNameContainingOrLastNameContaining(String UserName, String FirstName, String LastName, Pageable pageable);
}
My question: Is there a better way or more efficient way to achieve querying the user entity ?
As mentioned in the comments, what you're looking for is a fuzzy search. This is not something you can easily do within a database, but there are separate search engines that you can use:
Apache Solr (platform based on Apache Lucene)
ElasticSearch
Hibernate Search (Hibernate integration with Apache Lucene)
...
When using such solution, you'll have to index your entities into your search engine as well. Spring Data can help you with that since there is also a library for Solr.
First of all you need a new class that represents how your entity will look like in Solr. Be aware that you want to "flatten" everything if you would have nested relations:
#Document
public class UserDocument {
#Id
#Indexed("id")
private String id;
#Indexed("firstName")
private String firstName;
#Indexed("lastName")
private String lastName;
#Indexed("userName")
private String userName;
// ...
}
After that, you can write a repository like you're used to with Spring Data:
public interface UserDocumentRepository extends SolrCrudRepository<UserDocument, String> {
#Query("userName:?0 OR firstName:?0 OR lastName:?0")
List<UserDocument> findAll(String searchTerm);
}
After that, you can do something like this:
public User create(User input) {
// Create user in database
documentRepository.save(new UserDocument(input.getFirstName(), input.getLastName(), input.getUserName());
}
And you can query for fuzzy searches by using the repository as well:
documentRepository.findAll("vickz~3");
This will use the query that I just wrote, and will look first firstnames, lastnames or usernames containing vickz. The ~3 at the end is a special syntax to indicate that the name can be 3 characters different from the one I just used (= edit distance).
However, this will return the UserDocument Solr entities. If you want to get the entities, you'll have to look them up as well, which can be done by their username:
List<String> usernames = documentRepository
.findAll("vickz~3")
.stream()
.map(UserDocument::getUserName)
.collect(Collectors.toList());
repository.findByUsername(usernames); // Look in database for users matching those usernames

Resources