Springboot 3.0 Jakarta field validations - spring-boot

As javax validations not supported in springboot 3.0. How to do field validations using Jakarta.
imports
import jakarta.persistence.Entity;
import jakarta.persistence.NotNull;
import jakarta.persistence.Pattern;
#Entity
#Data
public class Users{
#NotNull
#NotEmpty
Private String username;
#Pattern
Private String username;
#NotNull
Private String username;
}
Controller
public class UsersController{
public void saveUser(#Valid #RequestBody Users user){
repo.save();
}
}
As javax validations not supported in springboot 3.0. How to do field validations using Jakarta.
imports
import jakarta.persistence.Entity;
import jakarta.persistence.NotNull;
import jakarta.persistence.Pattern;
#Entity
#Data
public class Users{
#NotNull
#NotEmpty
Private String username;
#Pattern
Private String username;
#NotNull
Private String username;
}
Controller
#PostMapping("/save")
public class UsersController{
public void saveUser(#Valid #RequestBody Users user){
repo.save();
}
}

Related

Spring Boot User Validation

I need a custom validator in Spring Boot(version 2.7.x). My User class is defined as:
class User{
private String email;
private String phone;
private String name;
private String address;
private String city;
private String country;
private String postalCode;
//getters and setters
}
I'm trying to validate the following requirements:
Either phone or email or a combination of (name+address+city+country+postalCode) is mandatory
If (name+address+city+country+postalCode) is present, they should be not null.
Please help with your suggestions as to how do I go about in implementing it.
you can use JSR-303 valiation implementation that hibernate-validator
and it is conventient to use annotation for valiate which
is in package javax.validation.constraints
here is code sample that
you can use #NotNull annotation above Field that mark the field should be not null
entity
class User{
private String email;
private String phone;
private String name;
#NotNull(message = "address should be not null")
private String address;
private String city;
private String country;
private String postalCode;
//getters and setters
}
validatorUtil
#Slf4j
public class ValidatorUtil {
static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
public static <T> Set<ConstraintViolation<T>> validateOne(T t , Class<?>... group) {
Set<ConstraintViolation<T>> validateResult = validator.validate(t,group);
return validateResult;
}
}
valiatorTest
#Slf4j
public class ValiatorTest {
#Test
public void vailator(){
User accountInfo = new User();
Set<ConstraintViolation<User>> constraintViolations = ValidatorUtil.validateOne(accountInfo);
Assertions.assertTrue(CollectionUtil.isNotEmpty(constraintViolations));
}
}
if you build project with maven ,add hibernate-validator dependency to pom
<properties>
<hibernate.validator.version>6.0.14.Final</hibernate.validator.version>
</properties>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate.validator.version}</version>
</dependency>
if you want learn more , please accroding to this article Which #NotNull Java annotation should I use?!

Consider defining a bean of type 'int' in your configuration[SpringBoot]

its my first time crating api in spring boot, i'm trying to create transaction api. when i'm running the application i'm getting this error
Description:
Parameter 0 of constructor in TransactionService.transactionService.modal.TransactionRequest required a bean of type 'int' that could not be found.
Action:
Consider defining a bean of type 'int' in your configuration.
Modal package:
TransactionEntity
#Getter
#Setter
#Builder
#Entity
public class TransactionEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int transactionId;
#NotNull
#Column(unique = true)
private UUID externalId;
#NotNull
private int userId;
#NotNull
private int merchantId;
#NotNull
private int clientReferenceId;
#NotNull
private double amount;
#Enumerated(EnumType.STRING)
#NotNull
private TransactionStatus status;
#NotNull
private String createdBy;
private String updatedBy;
#NotNull
private LocalDateTime createdAt;
#NotNull
private LocalDateTime updatedAt;
}
TransactionRequest
#Component
#Data
#Builder
public class TransactionRequest {
private int userId;
private int merchantId;
private int clientReferenceId;
private double amount;
private String createdBy;
}
TransactionResponse
#Component
#Data
#Builder
public class TransactionResponse {
private int userId;
private int merchantId;
private int clientReferenceId;
private double amount;
private LocalDateTime createdAt;
private TransactionStatus status;
}
TransactionDao
#Component
// Dao class
public class TransactionDao {
#Autowired
TransactionRepository transactionRepository;
TransactionEntity transactionEntity;
public TransactionResponse createTransaction(TransactionRequest transactionRequest){
LocalDateTime cuurentTime = LocalDateTime.now();
transactionEntity.builder().userId(transactionRequest.getUserId())
.merchantId(transactionRequest.getMerchantId())
.clientReferenceId(transactionRequest.getClientReferenceId())
.amount(transactionRequest.getAmount())
.createdBy(transactionRequest.getCreatedBy())
.createdAt(cuurentTime)
.updatedAt(cuurentTime)
.externalId(UUID.randomUUID())
.status(TransactionStatus.CREATED);
transactionRepository.save(transactionEntity);
return TransactionResponse.builder().status(transactionEntity.getStatus())
.createdAt(transactionEntity.getCreatedAt()).build();
}
}
TransactionService
#Service
public class TransactoinService {
#Autowired
public TransactionDao transactionDao;
public TransactionResponse createTransaction(TransactionRequest transactionRequest){
return transactionDao.createTransaction(transactionRequest);
}
}
TransactionController
#RestController
public class TransactionController {
#Autowired
TransactoinService transactoinService;
#PostMapping
TransactionResponse createTransaction(#RequestBody TransactionRequest transactionRequest){
return transactoinService.createTransaction(transactionRequest);
}
}
The TransactionRequest is annotated as #Component so spring boot autoscan will try to create a #Bean out that class.
It is also annotated with #Data so at the time of creating the bean Spring boot is trying to inject other beans as arguments into the all args constructor, and it is not finding an "int" bean to inject into the constructor.
I am guessing that the transaction response should not be a #Component or at least not a Singleton bean.
You should not create your POJO classes as a Spring Bean. Remove #Component annotation in your TransactionRequest and TransactionResponse POJO classes.

I18n for custom error messages into JPA entity

I looking to understand how to internationalize JPA entity error message. I understand how its work into a controller using autowired MessageSource but in my case I want to do this into a JPA entity. I'm not intresting about using the same way as the controller issue because I think is not optimized to autowired the full MessageSource on this entity. If someone have a simple example to show me how its work with a simple entity like mine. My project using spring-boot 2.2 ; JPA ; and thymeleaf.
The entity I using:
package com.bananasplit.weblab2.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
#Entity
#Table(name = "todo")
public class Todo {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "name", nullable = false)
#NotEmpty
#Size(min=2, max=30) // error message is already internationalized here with spring-boot
private String name;
#Column(name = "category", nullable = false)
#NotEmpty
#Pattern(regexp="(WORK|PERSONAL|SPECIAL)",
message="Category must be WORK or PERSONNAL or SPECIAL.") // here is the message I want to internationalize
private String category;
public Todo() {}
public Todo(String name, String category) {
this.name = name;
this.category = category;
}
#Override
public String toString() {
return String.format(
"Todo[id=%d, name='%s', category='%s']",
id, name, category);
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
}
By default Spring boot uses this ValidationMessages.properties but you can override by adding this file in resources.
#Size(min=2, max=30, message="{empty.todo.name")
private String name;
In ValidationMessages.properties file
empty.todo.name = Cannot be blank
If you want to manage which package messages should be scanned by Spring then should follow this link

How to cache Spring Data JPA Projections

I am running Spring Boot 1.5.1 with Spring Data JPA repositories. I have added a method to my User repository that makes use of JPA projections(UserProfile) which works great. I now wish to cache the results of that method in my Service layer which should return a result of type Page< UserProfile > as shown
The JPA Projection.
public interface UserProfile extends Serializable {
long getId();
#Value("#{target.firstname} #{target.othernames}")
String getFullName();
String getFirstname();
String getOthernames();
String getGender();
String getEnabled();
#Value("#{T(System).currentTimeMillis()-target.birthday.getTime()}")
long getBirthday();
}
The User Entity.
#Entity
#Cacheable(true)
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User implements Serializable {
private static final long serialVersionUID = 6756059251848061768L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Column
private String firstname;
#Column
private String othernames;
#Column
private String gender;
#Column
private String photoname;
#Column
private Date birthday;
#Column
private String username;
#Column
private Boolean enabled;
#Column
private String password;
#ElementCollection
private Map<String,String> phonenumbers = new HashMap<String,String>(0);
#JsonBackReference
#OneToMany(cascade = CascadeType.ALL, orphanRemoval=true)
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<Address> addresses = new ArrayList<Address>(0);
//Omitted Getters and Setters
#Override
public int hashCode() {...}
#Override
public boolean equals(Object obj) {...}
}
The User repository.
#Repository
public interface UserRepository extends JpaRepository<User, Long> {
public Page<UserProfile> findAllUserProfilesBy(Pageable pageable);
}
The User service implementation.
#Service
#Transactional(readOnly=true)
public class UserServiceImpl implements UserService {
#Autowired
UserRepository UserRepository;
#Override
#Cacheable("users")
public Page<UserProfile> findAllUserProfiles(Pageable pageable) {
//simulateSlowService();
return UserRepository.findAllUserProfilesBy(pageable);
}
}
However I get the following exception when the service method gets called.
java.lang.RuntimeException: Class org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor does not implement Serializable or externalizable
How should I go about caching the result of the service method?
Any help is greatly appreciated.

Object is not an instance of a persistable class warning with Spring boot and Neo4j

I have a pretty straightforward class called User which is supposed to create user objects containing user information and login details.
package com.example.domain;
import org.neo4j.ogm.annotation.GraphId;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Relationship;
import java.util.HashSet;
import java.util.Set;
#NodeEntity
public class User {
public User() {}
#GraphId
private Long id;
private String username;
private String password;
private String name;
private String email;
private String Role;
#Relationship(type="BELONGS_TO", direction = Relationship.INCOMING)
Set<Item> items = new HashSet<>();
public User(String name, String username, String password, String email) {
this.name = name;
this.username = username;
this.password = password;
this.email = email;
}
// Getters and setters below for private fields...
}
The controller creating the object looks like this:
#RequestMapping(value = "/register",method = RequestMethod.POST)
public String register(Model model,
#ModelAttribute(value="name") String name,
#ModelAttribute(value="username") String username,
#ModelAttribute(value="email") String email,
#ModelAttribute(value="password") String password,
#ModelAttribute(value="confirmPassword") String confirmPassword) {
if(!password.equals(confirmPassword)) {
model.addAttribute("error", true);
return "register";
}
User userEntity=new User(name,username,password,email);
userManagementService.save(userEntity); //<------The object is created but the error occures during persistance
return "login";
}
and my user management service looks like this:
public interface UserManagementService {
List<User> listAll();
User save(User user);
User findUser(String username);
}
What makes the User class, not an instance of a persistable class. What are the characteristics of a persistable class and how can I make User a persistable class?
Have you configured the OGM somewhere? Either in a Java configuration or in a ogm.properties file? You'll need to specify the driver type and tell the SessionFactory where to look for your domain objects.
OGM config reference: https://neo4j.com/docs/ogm-manual/2.1/reference/#reference:configuration
SessionFactory config reference: https://neo4j.com/docs/ogm-manual/2.1/reference/#reference:connecting:session-factory

Resources