Spring Boot - how to validate nested enteties - java

So lets say I have User object like this
#Entity
public class User {
#Id
#GeneratedValue
private long id;
private String name;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "address", referencedColumnName = "id")
private Address address;
}
#Entity
public class Address {
#Id
#GeneratedValue
private long id;
private String city;
private String country;
}
Now I don't want to write validation annotations in entities. What I would like to do is validate User in #RestController like this
#RestController
public class InvoiceController {
#RequestMapping(value="/users/add", method = RequestMethod.POST)
public Invoice addInvoice(#Validated #RequestBody ValidUser user) {
... do stuff
}
}
The validation annotations would be in ValidUser being like this.
public class ValidUser extends User {
#NotNull
private String name;
#Valid
private Address address;
}
public class ValidAddress extends Address{
#NotNull
private String city;
#NotNull
private String country;
}
The validation works when I remove the address field from the ValidUser but not when it is there. How can I make address validation also work?

Related

#GetMapping used to retrive item gives a responce of infinite loop of foreignkey object

i am new in spring boot and i could not find solution for this for a day now.
#GetMapping used to retrive item gives a responce of infinite loop of foreignkey object "user".
why am i getting this infinite loop?
how to fix it?
user object in infinite loop(the problem)
result that i want
item entity
#Entity
public class Item{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long ItemId;
#ManyToOne
#JoinColumn(name = "owner_id")
private User user;
private String ItemName;
// #Column(columnDefinition="text")
private String Description;
private double Price;
private int AvailableQuantity;
private double shippingWeight;
// #Transient
// private MultipartFile Picture;
#Enumerated(value = EnumType.STRING)
private Category category;
#OneToMany(mappedBy = "item")
#JsonIgnore
private List<CartItem> CartItemList;
}
user entity
#Entity
#Table(name = "Utilisateur")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idU;
private String username;
private String password;
private String firstname;
private String lastname;
private String gender;
private Long phone;
private String adress;
#Temporal(TemporalType.DATE)
private Date dateofbirth;
private int rating;
private String email;
public Role role;
private Integer status;
#OneToMany(mappedBy = "user")
private List<Item> ItemList;
}
item service
#Service
public class ItemService implements ItemServiceInterface{
#Autowired
ItemRepository itemrepository;
public Optional<Item> getItemById(long id){
return itemrepository.findById(id);
}
}
item controller
#RestController
public class ItemControl {
#Autowired
ItemServiceInterface itemservice;
#GetMapping("/getitem/{id}")
public Optional<Item> getitembyid(#PathVariable Long id) {
return itemservice.getItemById(id);
}
}
You can use combination of #JsonManagedReference and #JsonBackReference to discourage Jackson from infinite serialization.
#Entity
#Table(name = "Utilisateur")
public class User {
// omitted
#JsonManagedReference
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Item> ItemList;
}
#Entity
public class Item{
// omitted
#JsonBackReference
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "owner_id")
private User user;
}
More details could be found here https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
You can make use of lazy loading to cut the dependency loop between user and item. However, following that approach might potentially affect other parts of your projects because other codes might use the entity with an assumption that item list in user entity is already eager fetched.
A better way is not return the entity object directly to the REST response. You can define a data model for the rest response and convert the entity to that model in your service class. This way, you can completely control what to return and not to.
Another approach if you still want to use the entity as response: https://www.baeldung.com/spring-data-jpa-named-entity-graphs. This way, you can define when to use the lazy load with each specific query.

Spring DATA - How to load a Collections of ids for an ManyToMany relation without load the whole LazyProxyObject [duplicate]

I have two Entities in my Spring-Boot Application:
User.java
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
String firstname;
String lastname;
String username;
String password;
}
and
Role.java
Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
String name;
String description;
}
for my MySql database
I have excluded the getter and setter methods for this question.
I want to realise a Many-to-Many-Relationship between both Entities. Every user should be able to assign multiple roles to himself
I already Created a mapping table for both tables in my database. It has the rows
user_id
role_id.
I also created a new Entity UserRole.java which looks like this:
#Entity
#Table(name = "user_role")
public class UserRole implements Serializable{
private User user;
private Role role;
#Id
#ManyToOne
#JoinColumn(name = "user_id")
public User getuser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Id
#ManyToOne
#JoinColumn(name = "role_id")
public Role getrole(){
return role;
}
public void setRole(Role role){
this.role = role;
}
}
Now my question: is this construction correct? If yes, how do i add existing roles to an existing user and get the roles of this user in spring-boot?
You can find any tutorial connected with many-to-many relationship using Hibernate/Spring Data, example:
Spring Data many-to-many
With your model it's simple to add the relationship mappings, like this:
#Entity
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String description;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable
private Set<User> users;
}
and this:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstname;
private String lastname;
private String username;
private String password;
#ManyToMany(mappedBy = "users")
private Set<Role> roles;
}

Validation a DTO with two entity

I have a DTO with two entity. How can I validate these entities?
What annotation should I use?
I use rest api, JSON, spring boot.
I know how to validate one entity. But I don't know what to do with DTO.
#PostMapping
public ResponseEntity<?> create(#Valid #RequestBody DTOClient client) {
....
return responseEntity;
}
public class DTOClient{
//What I should use here to validate these entities?
private Client client;
private Skill skill;
}
#Entity
public class Client{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String first_name;
private String last_name;
}
#Entity
public class Skill{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private int year;
}
Use javax.validation for the fields which you want to validate. Below code is an example to validate first_name in client object should not null or blank.
#PostMapping
public ResponseEntity<?> create(#Valid #RequestBody DTOClient client) {
....
return responseEntity;
}
public class DTOClient{
//What I should use here to validate these entities?
#Valid
#NotNull(message="client should not null")
private Client client;
private Skill skill;
}
#Entity
public class Client{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotBlank(message="first name of client should not be null or blank")
private String first_name;
private String last_name;
}
#Entity
public class Skill{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private int year;
}
In short, you need use #Valid for Bean, like controller methods' params and the fields which not primary. And Constraint annotations for the fields which need validate.

Spring JPA mapping - first steps

I have class User:
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable
private List<Role> roles;
}
Class Owner inherits from User
#Entity
public class Owner extends User {
private String pesel;
private String adress;
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private List<Pet> pets;
}
and Owner had Pet
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
#ManyToOne
private Owner owner;
}
Why when starting the application gets the error:
org.springframework.data.mapping.PropertyReferenceException: No
property user found for type Pet!
--EDIT
First I have version, which was as follows:
now I try to share User instance to a doctor and the owner of the animal
The problem is that I do not know whether I am doing the mapping , and therefore wanted to ask whether it must look like
--edit2
I've simplified the scheme just a bit to better illustrate what happens
--edit3
Currently my Object's was presented:
#Entity
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
}
User
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable(name="user_roles")
private List<Role> roles;
}
PetOwner
#Entity
public class PetOwner extends User {
private String pesel;
private String adress;
#OneToMany(mappedBy="petOwner")
private List<Pet> pets;
}
I replace
#ManyToOne
private PetOwner petOwner;
for
#ManyToOne
private Owner petOwner;
and it works. Do you have a PetOwner class?
Also provide the log error to get more information about it

#OneToOne Hibernate with annotations. Can't properly save

I can't make my foreign keys auto generate using hibernate and jpa with annotations. Everything seems ok, The entries are saved in database. All the date come from one form which, when submited creates an User object with ModelAttribute and then saves it in Database.
Here are my beans. Anything else i should add ?
#Entity
#Table(name="adress")
public class Adress implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="adress_id")
private Integer adressId;
#NotBlank(message="The city must be completed")
#Column(name="city")
#Size(min=5,max=30)
private String city;
#NotBlank(message="The street must be completed")
#Column(name="street")
#Size(min=5,max=30)
private String street;
#NotNull(message="The street number must be completed")
#NumberFormat
#Column(name="street_no")
private Integer streetNo;
#OneToOne
#JoinColumn(name="user_id")
private User user;}
and the other one:
#Entity
#Table(name="users")
public class User implements Serializable {
#Id
#Column(name="user_id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer userId;
#NotBlank(message="Username can't be blank")
#Size(min=5,max=30)
#Column(name="username")
private String username;
#NotBlank(message="Password field can't be blank")
#Size(min=5,max=30)
#Column(name="password")
private String password;
#NumberFormat
#NotNull(message="Age field must not be blank")
#Column(name="age")
private Integer age;
#Column(name="message")
#Size(min=0,max=100)
private String message;
#Column(name="date")
#DateTimeFormat(pattern="dd/mm/yyyy")
private Date dateCreated;
#OneToOne(mappedBy="user",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private Adress adress;
+getters and setters for them
public void save(T entity){
sessionFactory.getCurrentSession().save(entity);
}
If I understand you correctly and you're trying to get Hibernate to set the foreign key on your related record this might help. Try getting rid of mappedBy and instead specify the JoinColumn. This works for me on a one to many:
The order:
#Entity
#Table(name = "`order`")
public class Order implements Serializable {
#Id
#GeneratedValue
private Long id;
// Order columns...
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "order_id")
private Set<Item> items;
}
The item:
#Entity
#Table(name = "item")
public class Item implements Serializable {
#Id
#GeneratedValue
private Long id;
// Item columns...
#ManyToOne(optional = false)
#JoinColumn(name = "order_id", referencedColumnName = "id", nullable = false)
private Order order;
}
in adress class
#OneToOne(mappedBy="adress")
private User user;
and in user class
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER,optional=false)
#PrimaryKeyJoinColumn
private Adress adress;

Categories