I would like to conditionally validate certain things on my models in my Spring Boot application based upon which route the model is being validated by.
I have two routes, one for signing up for logging in. The one for logging in simply requires a username and password. The one for signing up requires an email, username and password. I would like to use the same model using javax.validation.constraints on both routes.
User.java `
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable=false,unique = true)
@NotBlank(message = "email is blank")
@Email(message = "invalid email")
private String email;
@Column(nullable=false,updatable = false,unique = true)
@Size(min = 8, max = 32, message = "username must be between 8 and 32 characters")
private String username;
@Column(nullable=false)
@NotBlank(message = "missing password")
@Size(min = 8, max = 32, message = "password must be between 8 and 32 characters")
private String password;
@Column(columnDefinition = "text")
private String about;
@Column(nullable=false,updatable = false)
@CreationTimestamp
private LocalDateTime createdAt;
private LocalDateTime passwordChangedAt;
private LocalDateTime aboutChangedAt;
UserController.java
@CrossOrigin(origins = "*", maxAge = 3600)
@RestController
@RequestMapping("/api/auth")
public class UserController {
private final AuthenticationManager authenticationManager;
private final UserRepository userRepository;
private final RoleRepository roleRepository;
private final PasswordEncoder encoder;
private final JwtUtils jwtUtils;
public UserController(AuthenticationManager authenticationManager, UserRepository userRepository, RoleRepository roleRepository, PasswordEncoder encoder, JwtUtils jwtUtils) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
this.roleRepository = roleRepository;
this.encoder = encoder;
this.jwtUtils = jwtUtils;
}
@PostMapping("/signin")
public ResponseEntity<?> authenticateUser(@Valid @RequestBody User loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
@PostMapping("/signup")
public ResponseEntity<?> registerUser(@Valid @RequestBody User signUpRequest) {
if (userRepository.existsByUsername(signUpRequest.getUsername())) {
return ResponseEntity
.badRequest()
.body(new MessageResponse("Error: Username is already taken!"));
}
if (userRepository.existsByEmail(signUpRequest.getEmail())) {
return ResponseEntity
.badRequest()
.body(new MessageResponse("Error: Email is already in use!"));
}
// Create new user's account
User user = new User(signUpRequest.getUsername(),
signUpRequest.getEmail(),
encoder.encode(signUpRequest.getPassword()));
Set<String> strRoles = signUpRequest.getRole();
Set<Role> roles = new HashSet<>();
if (strRoles == null) {
Role userRole = roleRepository.findByName(ERole.ROLE_USER)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(userRole);
} else {
strRoles.forEach(role -> {
switch (role) {
case "admin":
Role adminRole = roleRepository.findByName(ERole.ROLE_ADMIN)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(adminRole);
break;
case "mod":
Role modRole = roleRepository.findByName(ERole.ROLE_MODERATOR)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(modRole);
break;
default:
Role userRole = roleRepository.findByName(ERole.ROLE_USER)
.orElseThrow(() -> new RuntimeException("Error: Role is not found."));
roles.add(userRole);
}
});
}
user.setRoles(roles);
userRepository.save(user);
return ResponseEntity.ok(new MessageResponse("User registered successfully!"));
}
}
`
I would like to use the same User model/entity for both. Is there a way to do this?
I know I can create different request templates that I would then map to a model, however I am curious if there is a more concise way to do this using annotations.
CodePudding user response:
While you annotate your Model method parameter with @Valid
, you can instead use Spring's @Validated
annotation.
This is similar to already answered StackOverflow question.
You can read on using validation Groups from this baeldung blog.