I wrote a custom validation in spring boot. The custom validation is meant to check if two fields match. Everything works fine until i try to submit the form. Boom i experience the error:
javax.validation.ConstraintViolationException: Validation failed for classes [com.joker.SampleAuthenticationWebApp.model.User] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='Passwords do not match!', propertyPath=con_password, rootBeanClass=class com.joker.SampleAuthenticationWebApp.model.User, messageTemplate='Passwords do not match!'}
]
This problem has really hindered my learning progress. Your help would be very much appreciated.
PS: I've Scraped SO in search of a solution but all was to no avail.The Annotation:
package com.joker.SampleAuthenticationWebApp.validator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
#Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Constraint(validatedBy = FieldsValueMatchValidator.class)
public #interface FieldsValueMatch {
String message() default "Fields values don't match!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String field();
String fieldMatch();
#Target({ ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#interface List {
FieldsValueMatch[] value();
}
}
The Validator:
package com.joker.SampleAuthenticationWebApp.validator;
import com.joker.SampleAuthenticationWebApp.model.User;
import org.springframework.beans.BeanWrapperImpl;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class FieldsValueMatchValidator implements ConstraintValidator<FieldsValueMatch, Object> {
private String field;
private String fieldMatch;
#Override
public void initialize(FieldsValueMatch constraintAnnotation) {
this.field = constraintAnnotation.field();
this.fieldMatch = constraintAnnotation.fieldMatch();
}
#Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
try {
final Object fieldValue = new BeanWrapperImpl(value).getPropertyValue(field);
final Object fieldMatchValue = new BeanWrapperImpl(value).getPropertyValue(fieldMatch);
boolean isValid = fieldValue == null && fieldMatchValue == null || fieldValue != null && fieldValue.equals(fieldMatchValue);
if (!isValid) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate()).addPropertyNode(fieldMatch).addConstraintViolation();
return false;
}
return isValid;
}
catch (final Exception ignore) {
// ignore
}
return true;
}
}
The User Model:
package com.joker.SampleAuthenticationWebApp.model;
import com.joker.SampleAuthenticationWebApp.validator.FieldsValueMatch;
import org.hibernate.validator.constraints.Length;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Set;
#Entity
#Table(name = "auth_user")
#FieldsValueMatch(field = "password", fieldMatch = "con_password", message = "Passwords do not match!")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
#Column(name = "auth_user_id", unique = true)
private int id;
#NotNull
#NotEmpty(message = "First name is compulsory")
#Column(name = "firstname")
private String firstname;
#NotNull
#NotEmpty(message = "Last name is compulsory")
#Column(name = "lastname")
private String lastname;
#NotNull
#NotEmpty(message = "Email is compulsory")
#Email
#Column(name = "email")
private String email;
#NotNull
#Column(name = "phone")
private String phone;
#NotNull
#NotEmpty(message = "Password is compulsory")
#Length(min = 5, message = "Password length should be at least 5 characters")
#Column(name = "password")
private String password;
#NotEmpty(message = "Confirm Password field is compulsory")
#Transient
private String con_password;
#NotNull
#Column(name = "enabled")
private int enabled;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "auth_user_role", joinColumns = #JoinColumn(name = "auth_user_id"), inverseJoinColumns = #JoinColumn(name = "auth_role_id"))
private Set<Role> roles;
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 getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCon_password() {
return con_password;
}
public void setCon_password(String con_password) {
this.con_password = con_password;
}
public int getEnabled() {
return enabled;
}
public void setEnabled(int enabled) {
this.enabled = enabled;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
I experienced this problem too . The only way to solve this is to include the annotations of #ModelAttribute and #Valid on your controller class for the bean you want to check weather the condition of #FieldsValueMatch(field = "password", fieldMatch = "con_password", message = "Passwords do not match!") is true , after that include the BindingResult right after the bean you want to check . Check if BindigResult hasErrors(), and return what is your next step .
EX:
#PostMapping("/signup")
public String signup(#ModelAttribute(name = "user") #Valid User user,BindingResult result,Model model)
if (result.hasErrors())
return "signup_form";
Hope this is clear .
Related
I'm developing a crud API with a post method, when testing this method in my postman it returns the error
2023-02-15T13:34:35.528-03:00 WARN 8792 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public org.springframework.http.ResponseEntity<java.lang.Object> com.api.order_control.controllers.OrderController.saveOrder(com.api.order_control.dtos.OrderDto) with 2 errors: [Field error in object 'orderDto' on field 'doorNumber': rejected value [null]; codes [NotBlank.orderDto.doorNumber,NotBlank.doorNumber,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [orderDto.doorNumber,doorNumber]; arguments []; default message [doorNumber]]; default message [must not be blank]] [Field error in object 'orderDto' on field 'block': rejected value [null]; codes [NotBlank.orderDto.block,NotBlank.block,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [orderDto.block,block]; arguments []; default message [block]]; default message [must not be blank]] ]
I couldn't understand why my blank cannot work with this method and why this error. can anybody help me?
model
package com.api.order_control.models;
import jakarta.persistence.*;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.UUID;
#Entity
#Table(name = "restaurant_orders")
public class OrderModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
#Column(nullable = false, length = 11)
private String customerName;
#Column(nullable = false, length = 15)
private String phoneNumber;
#Column(nullable = false, length = 25)
private String address;
#Column(nullable = false, length = 10)
private String doorNumber;
#Column(length = 5)
private String block;
#Column(nullable = false, length = 30)
private String orderNote;
#Column(nullable = false)
private Float price;
#Column(nullable = false)
private LocalDateTime registrationDate;
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getDoorNumber() {
return doorNumber;
}
public void setDoorNumber(String doorNumber) {
this.doorNumber = doorNumber;
}
public String getBlock() {
return block;
}
public void setBlock(String block) {
this.block = block;
}
public String getOrderNote() {
return orderNote;
}
public void setOrderNote(String order) {
this.orderNote = orderNote;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public LocalDateTime getRegistrationDate() {
return registrationDate;
}
public void setRegistrationDate(LocalDateTime registrationDate) {
this.registrationDate = registrationDate;
}
}
dto pack
package com.api.order_control.dtos;
import jakarta.validation.constraints.NotBlank;
public class OrderDto {
#NotBlank
private String customerName;
#NotBlank
private String phoneNumber;
#NotBlank
private String address;
#NotBlank
private String doorNumber;
#NotBlank
private String block;
#NotBlank
private String orderNote;
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String doorNumber() {
return doorNumber;
}
public void doorNumber(String doorName) {
this.doorNumber = doorName;
}
public String getBlock() {
return block;
}
public void setBlock(String block) {
this.block = block;
}
public String getOrderNote() {
return orderNote;
}
public void setOrderNote(String orderNote) {
this.orderNote = orderNote;
}
}
controller with post
package com.api.order_control.controllers;
import com.api.order_control.dtos.OrderDto;
import com.api.order_control.models.OrderModel;
import com.api.order_control.services.OrderService;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
#RestController
#CrossOrigin(origins = "*", maxAge = 3600)
#RequestMapping("/orders")
public class OrderController {
final OrderService orderService;
public OrderController(OrderService orderService) {
this.orderService = orderService;
}
#PostMapping
public ResponseEntity<Object> saveOrder(#RequestBody #Valid OrderDto orderDto) {
var orderModel = new OrderModel();
BeanUtils.copyProperties(orderDto, orderModel);
orderModel.setRegistrationDate(LocalDateTime.now(ZoneId.of("UTC")));
orderModel.setPrice(70.8f);
return ResponseEntity.status(HttpStatus.CREATED).body(orderService.save(orderModel));
}
}
I had already had a blank error because I was using a float, but in this case "numberDoor" is just a string. What is the reason for this error?
Postman request
{
"customerName": "Ryan",
"phoneNumber": "1 99859 5854",
"address": "St Street Vl 190",
"doorNumber": "5",
"orderNote": "Pepperoni Pizza"
}
It's a validation error.
You don't pass block in your post method, but in DTO this field annotated with #NotBlack
You didn't provide eligible setter for doorNumber. As a result, this field is null in your DTO object, but again, is annotated with #NotBlack. The setter name must be setDoorNumber(String value) for that field
I have the following situation: A user entity can have a lot of friends who are also users themselves.
To resolve this situation I used this answer Hibernate recursive many-to-many association with the same entity
It works! But not completely. After I put data into table TBL_FRIENDS the data is saved as I expected but then the getById function of the interface JpaRepository returns NULL for users I entered into the TBL_FRIENDS table.
this is my code:
package com.example.demo.user;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
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.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "username", nullable = false)
private String username;
#Column(name = "gender", nullable = false)
private String gender;
#Column(name = "date", nullable = true)
private Date date;
#Column(name = "phone", nullable = false)
private String phone;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "description", nullable = true)
private String description;
#Column(name = "hashpassword", nullable = false)
private String hashpassword;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="tbl_friends",
joinColumns=#JoinColumn(name="personId"),
inverseJoinColumns=#JoinColumn(name="friendId")
)
private List<User> friends = new ArrayList<>();
#ManyToMany(mappedBy = "friends")
#JoinTable(name="tbl_friends",
joinColumns=#JoinColumn(name="friendId"),
inverseJoinColumns=#JoinColumn(name="personId")
)
private List<User> friendOf = new ArrayList<>();
protected User() {
}
public User(Long id, String username, String gender,Date date, String phone, String email, String description,String hashpassword ) {
super();
this.id = id;
this.username = username;
this.gender = gender;
this.date = date;
this.phone = phone;
this.email = email;
this.description = description;
this.hashpassword = hashpassword;
}
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 getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getHashpassword() {
return hashpassword;
}
public void setHashpassword(String hashpassword) {
this.hashpassword = hashpassword;
}
public List<User> getFriends() {
return friends;
}
public void addFriends(User friend) {
this.friends.add(friend);
}
public List<User> getFriendOf() {
return friendOf;
}
public void addFriendOf(User friend) {
this.friendOf.add(friend);
}
#Override
public int hashCode() {
return Objects.hash(id);
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
return id == other.id;
}
}
public void insertUserAndFriends(User sourceUser,User targetUser) {
User su = userJpaRepository.getOne(sourceUser.getId());
su.addFriends(targetUser);
su.addFriendOf(targetUser);
userJpaRepository.save(su);
}
#PostMapping("/jpa/users/{userId}/friends")
public ResponseEntity<Void>insertFriends(#RequestBody Map<String,User> jason){
userJpaRepository.insertUserAndFriends(jason.get("sourceUser"),jason.get("targetUser"));
return ResponseEntity.ok().build();
}
#GetMapping("/jpa/users/{userId}")
public User getUser(#PathVariable Long userId){
return userJpaRepository.findById(userId).get();
}
I would like to hear any advice.:
Maybe your request has id's value is null or you can use :
#GeneratedValue(strategy = GenerationType.AUTO)
I am having a problem with my retriveUser method. When I run finbyid method it returns the same repeated values. You can see my repository, user, and userService classes and the result below.
[![findbyid method result][1]][1]
My User Repository Class
package io.javabrains.springsecurity.jpa;
import io.javabrains.*;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import io.javabrains.springsecurity.jpa.models.User;
#Repository
public interface UserRepository extends JpaRepository<User, Integer> {
Optional<User> findByUserName(String userName);
}
My User Class
#Entity
#Table(name="app_user")
public class User implements Serializable {
#Id
#GeneratedValue(strategy =GenerationType.IDENTITY)
private int id;
private String userName;
private String password;
private boolean active;
private String role;
private String city;
public User(String userName, boolean active, String role, String city) {
super();
this.userName = userName;
this.active = active;
this.role = role;
this.city = city;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "user_cities", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "city_id", referencedColumnName = "id"))
private Collection<UserCity> usercities = new ArrayList<UserCity>() ;
public Collection<UserCity> getUsercities() {
return usercities;
}
public void setUsercities(Collection<UserCity> usercities) {
this.usercities = usercities;
}
public User() {}
public int getId() {
return id;
}
public void setId(int 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 boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
My Service Class
#RestController
public class HomeResource {
#Autowired
private BCryptPasswordEncoder bcryptPasswordEncoder;
#Autowired
private WeatherService weatherService;
#Autowired
private CityRepository cityRepository;
#Autowired
private UserRepository userRepo;
#GetMapping("/")
public String home() {
return ("<h1>Welcome</h1>");
}
#GetMapping("/user")
public String user() {
return ("Welcome User");
}
#GetMapping("/admin")
public String admin() {
return ("<h1>Welcome Admin</h1>");
}
#GetMapping("/getCities")
public List<UserCity> getCities()
{
return cityRepository.findAll();
}
#GetMapping("/users/{id}")
public ResponseEntity<User> retriveUser(#PathVariable int id){
Optional<User> a=userRepo.findById(id);
return new ResponseEntity<User>(a.get(),HttpStatus.OK);
}
Thanks in advance for your help.
Sincerely
[1]: https://i.stack.imgur.com/gNhO7.png
The repeated value is a nested user from the usercities collection in a User object.
The user (id: 1) has a usercities collection containing one UserCity object (cityName: 'bursa' and users containing the same user (id: 1)). Thus, the user (id: 1) is recursively displayed.
You can add #JsonIgnore annotation to your property (usercities in User or users in UserCity) to cut the recursion.
Here is my User entity
package org.scd.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.scd.model.security.Role;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "USERS")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "FIRST_NAME", nullable = false, length = 45)
private String firstName;
#Column(name = "LAST_NAME", nullable = false, length = 45)
private String lastName;
#Column(name = "EMAIL", nullable = false, unique = true, length = 45)
private String email;
#Column(name = "PASSWORD", nullable = false, length = 256)
private String password;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>(0);
#OneToMany(mappedBy = "user",
fetch = FetchType.EAGER
)
private List<Position> positions;
public User() {
}
public User(String firstName, String lastName, String email, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setPassword(String password) {
this.password = password;
}
public List<Position> getPositions() {
return positions;
}
public void setPositions(List<Position> positions) {
this.positions = positions;
}
#JsonIgnore
public String getPassword() {
return password;
}
#JsonProperty("password")
public String getHiddenPassword() {
return "****";
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
Here is my Position entity
package org.scd.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.Date;
#Entity
#Table(name = "POSITIONS")
public class Position {
#Id
#GeneratedValue(strategy =GenerationType.IDENTITY)
private Long id;
#Column(name = "START_DATE", nullable = false)
private LocalDate creationDate;
#Column(name = "LATITUDE", nullable = false, length = 45)
private String latitude;
#Column(name = "LONGITUDE", nullable = false, length = 45)
private String longitude;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id", nullable = false, updatable = false)
#JsonIgnore
private User user;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Position )) return false;
return id != null && id.equals(((Position) o).getId());
}
#Override
public int hashCode() {
return 31;
}
public Position() {
}
public Position(LocalDate creationDate, String latitude, String longitude, User user) {
this.creationDate = creationDate;
this.latitude = latitude;
this.longitude = longitude;
this.user = user;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public LocalDate getCreationDate() {
return creationDate;
}
public void setCreationDate(LocalDate creationDate) {
this.creationDate = creationDate;
}
public String getLatitude() {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
Here is the GET request that doesn't work. I can only send the startDate and endDate as a String, but I need them to be in Date format.
#GetMapping(path = "/byUserIdAndTimePeriod/{userId}/{startDate}/{endDate}")
public ResponseEntity<List<Position>> getPositionByUserAndTimePeriod(#PathVariable Long userId, #PathVariable Date startDate, #PathVariable Date endDate) {
return new ResponseEntity<>(new ArrayList<Position>(positionService.getPositionByUserAndTimePeriod(userId,startDate,endDate)),HttpStatus.OK);
}
This one is the updated GET request that works
#GetMapping(path = "/byUserIdAndTimePeriod/{userId}/{startDate}/{endDate}")
public ResponseEntity<List<Position>> getPositionByUserAndTimePeriod(#PathVariable Long userId,
#PathVariable #DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate,
#PathVariable #DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) {
return new ResponseEntity<>(new ArrayList<Position>(positionService.getPositionByUserAndTimePeriod(userId,startDate,endDate)),HttpStatus.OK);
}
Here is the position service
#Override
public List<Position> getPositionByUserAndTimePeriod(Long userId, LocalDate startDate, LocalDate endDate) {
User user = new User();
user.setId(userId);
return positionRepository.findAllByUserAndCreationDateBetween(user,startDate,endDate);
}
Here is the position repository
List<Position> findAllByUserAndCreationDateBetween(User user, LocalDate startDate, LocalDate endDate);
Do you have any ideas as to how I should resolve this problem?
How should the GET request look? Should I modify some things in the service or other places?
Thanks for your time.
You have to add the #DateTimeFormat(pattern="yyy-MM-dd") annotation to the parameter:
#GetMapping(path = "/byUserIdAndTimePeriod/{userId}/{startDate}/{endDate}")
public ResponseEntity<List<Position>> getPositionByUserAndTimePeriod(#PathVariable Long userId,
#PathVariable Date startDate,
#PathVariable #DateTimeFormat(pattern="yyy-MM-dd") Date endDate) {
return new ResponseEntity<>(new ArrayList<Position>(positionService.getPositionByUserAndTimePeriod(userId,startDate,endDate)),HttpStatus.OK);
}
hoping I can get some assistance resolving a particular issue. I am basically trying to create a rest api endpoint that displays my one to one relationship between my User & UserProfile class. I am trying to do this using annotations but I'm not having any luck. I can't seem to return both the user info as well as associated profile info. Here are my classes
package com.account.service.model;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import javax.persistence.*;
import java.util.Date;
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String email;
private Boolean active;
#JsonIgnore
private String password;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date created_at;
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date updated_at;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
#JoinColumn(name = "user_id")
#JsonBackReference
private UserProfile userProfile;
public User(){}
public User(String email, Boolean active, String password, Date created_at, Date updated_at) {
this.email = email;
this.active = active;
this.password = password;
this.created_at = created_at;
this.updated_at = updated_at;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Boolean getActive() {
return active;
}
public void setActive(Boolean active) {
this.active = active;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreated_at() {
return created_at;
}
public void setCreated_at(Date created_at) {
this.created_at = created_at;
}
public Date getUpdated_at() {
return updated_at;
}
public void setUpdated_at(Date updated_at) {
this.updated_at = updated_at;
}
public UserProfile getUserProfile() {
return userProfile;
}
public void setUserProfile(UserProfile userProfile) {
this.userProfile = userProfile;
}
}
and here is the User Profile
package com.account.service.model;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
#Entity
#Table(name = "user_profiles")
public class UserProfile {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String first_name;
private String last_name;
#OneToOne(cascade = CascadeType.ALL, optional = false)
#JsonManagedReference
private User user;
public UserProfile(){}
public UserProfile(String first_name, String last_name, User user) {
this.first_name = first_name;
this.last_name = last_name;
this.user = user;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
The response I get is the following which is missing the profile association.
[
{
"id": 1,
"email": "ul#gmail.com",
"active": true,
"created_at": "2017-12-21",
"updated_at": "2017-12-21"
}
]
Any thoughts on what the issue could be?
The intention is to display the following:
[
{
"id": 1,
"email": "ul#gmail.com",
"active": true,
"created_at": "2017-12-21",
"updated_at": "2017-12-21",
"profile": {
"id": 1,
"first_name": "master",
"last_name": "splinter"
}
}
]
Figured it out, if anyone else is stuck on an issue like this please take a look at #JsonBackReference this should be used on your User class not on your Profile class.