Spring Boot User Validation - spring-boot

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?!

Related

Springboot 3.0 Jakarta field validations

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();
}
}

Spring Data JPA Redis : Cannot write custom method based query

I have configured Spring Data JPA with Redis and using RedisRepositories with provides methods like find(), findAll() etc. All these methods seem to be working just fine, but I am not able to write my custom method like.
RedisEntity findByGenderAndGrade(String gender, String grade);
RedisEntity is a simple POJO Entity class. If you want any more info, please let me know in messages.
Following is my entity:
#Data
#RedisHash("test1")
public class RedisEntity implements Serializable {
#Id
#GeneratedValue
private String id;
private String name;
private String gender;
private Integer grade;
}
Repository:
#Repository
public interface TestRepository extends JpaRepository<RedisEntity, String> {
List<RedisEntity> findAllByGender(String gender);
List<RedisEntity> findAllByGrade(Integer grade);
}
Service/Controller:
#Override
public List<RedisEntity> getById(String id) {
return testRepository.findById(id); //returns data perfectly.
}
#Override
public List<RedisEntity> getAllByGender(String gender) {
return testRepository.findAllByGender(gender); //returns []
}
#Override
public void saveEntity(RedisEntity redisEntity) {
testRepository.save(redisEntity); // saves it in redis perfectly.
}
Also,
findByGender and findAllByGender both give [], although I can see data in my redis database and save it as well.
As requested by FrançoisDupire,
#Configuration
public class RedisConfig {
#Autowired
private DeploymentProperties deploymentProperties;
private static Logger logger = LoggerFactory.getLogger(RedisConfig.class);
#Bean
JedisConnectionFactory jedisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration("localhost", 6379);
redisStandaloneConfiguration.setPassword(RedisPassword.of("root"));
return new JedisConnectionFactory(redisStandaloneConfiguration);
}
#Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
}
Also, I had referred this article: Baeldung article on Spring data redis
As mentioned by #JoshJ and verified by myself and others,
The solution to the problem is:
Adding #Indexed annotation
to all those columns/fields which need to be used with all finds.
#Data
#RedisHash("EmployeeDetails")
public class RedisEntity {
#Id
private String employeeId;
private String firstName;
private String lastName;
#Indexed
private String gender;
#Indexed
private String grade;
}
We have the Spring Data Redis Library which provides the scope to write the custom method.Attaching Sample code.
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.0.8.RELEASE</version>
</dependency>
Entity Definition
#Data
#RedisHash("EmployeeDetails")
public class RedisEntity {
#Id
private String employeeId;
private String firstName;
private String lastName;
private String gender;
private String grade;
}
Repository Definition
#Repository
public interface RedisEntityRepository extends CrudRepository<RedisEntity, String>{
List<RedisEntity> findAllByGenderAndGrade(String gender, String grade);
}
Implementation
#Component
public class RedisEntityImpl implements RedisEntityService {
#Autowired
private RedisEntityRepository redisEntityRepository;
#Override
public List<RedisEntity> getAllByGenderAndGrade(String gender, String grade) {
return redisEntityRepository.findAllByGenderAndGrade(gender,grade);
}
}
Properties
spring.cache.type = redis
spring.redis.host = localhost
spring.redis.port = 6379

Ignoring Nested properties in Jackson OnDemand

I am working on a spring boot application with Hibernate as ORM and Jackson as JSON serialiser .
I have three model objects and CRUD operations for all three models.
Class Student{
private Teacher teacher; // Teacher of the student — to be fetched eagerly
+Getter/Setter
}
class Teacher {
private List<Subject> subject; // List of subjects associated to that user— to be fetched eagerly
+Getter/Setter
}
class Subject {
private long subjectId
//Other subject properties
+ Getter/Setter
}
Whenever I trigger a get request for student info I get the teacher info which is correct where as I also receive Subject info as well which is unnecessary for me. In the same time when I request for Teacher info, I need Subject info should be associated to that for sure. If I use #JsonBackReference for subject I am losing it all the time. I am not sure how to achieve this.
Thanks in advance for your help!!
You can also annotate like this
Class Student{
#JsonIgnoreProperties("subject")
private Teacher teacher; // Teacher of the student — to be fetched eagerly
}
You can use JSON Views
From the spring blog:
public class View {
interface Summary {}
}
public class User {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private String firstname;
#JsonView(View.Summary.class)
private String lastname;
private String email;
private String address;
private String postalCode;
private String city;
private String country;
}
public class Message {
#JsonView(View.Summary.class)
private Long id;
#JsonView(View.Summary.class)
private LocalDate created;
#JsonView(View.Summary.class)
private String title;
#JsonView(View.Summary.class)
private User author;
private List<User> recipients;
private String body;
}
and in the controller
#RestController
public class MessageController {
#Autowired
private MessageService messageService;
#JsonView(View.Summary.class)
#RequestMapping("/")
public List<Message> getAllMessages() {
return messageService.getAll();
}
#RequestMapping("/{id}")
public Message getMessage(#PathVariable Long id) {
return messageService.get(id);
}
}
PS: No link to http://fasterxml.com/ as it's currently down.

want to autowire DAO class in my entity class

i have a method which i need to call in my entity class company.java.
but when i run my application it throws null pointer exception didn't fount that DAO object in entity class..
How can i get that object in entity class please help
This is my entity class..
package com.salebuild.model;
/**
* Define a company.
*
* #author mseritan
*/
#Entity
#Table(name = "company", uniqueConstraints = {#UniqueConstraint(columnNames = "name")})
#XmlRootElement
#XmlSeeAlso(value = ArrayList.class)
public class Company implements PublishableIF, Serializable, PersistableIF, HistoryIF, AddressableIF {
private static final Logger log = LoggerFactory.getLogger( Company.class );
#Autowired
private CompanyDAO companyDAO;
// CONSTANTS -----------------------------------------------------------------------------------
private static final long serialVersionUID = 1L;
// ATTRIBUTES ----------------------------------------------------------------------------------
private Long id;
#NotBlank
private String name;
private String formerName;
private CorporateTitle topLevelExec;
private List<CompanySite> sites;
private List<CompanyAlias> aliases;
#NotNull
private Industry industry;
private Company parentCompany;
private String emailTopology;
#NotNull
private Double revenue;
#NotNull
private Long numberEmployees;
private CustomerType.Type customerType;
private Boolean recruiter = false;
private int publishState;
private CompanyStatus status;
private Boolean excludeCompany = false;
private CompanyType companyType;
private String salesifyCompanyId;
private CompanySiteType companySiteType;
private String websiteUrl;
private String sourceVendor;
private String notes;
private List<CompanySpecializedRanking> specializedList = new ArrayList<CompanySpecializedRanking>();
#NotNull
private NAICSCode naicsCode;
#NotNull
private SICCode sicCode;
private Long version;
private List<Technology> technologies = new ArrayList<Technology>();
private List<CompanyContact> contacts;
private String phoneNumber;
private String faxNumber;
private String email;
private User userCreated;
private Date dateCreated;
private User userLastModified;
private Date dateLastModified;
private User userLastResearcher;
private Date dateLastResearcher;
#NotBlank
private String street1;
private String street2;
private String street3;
private String city;
private String zipCode;
private State state;
private Country country;
private String specRankingListName;
private Integer specRankingRank;
private Integer specRankingYear;
private String modifiedCompanyName;
private String formattedRevenue;
private String formattedEmployeeSize;
private List<JobPostingRaw> unconfirmedTechnologies;
// ACESSORS ------------------------------------------------------------------------------------
//getter setter for other fields //
this.specRankingYear = specRankingYear;
}
/**
* #param modifiedCompanyName
*
*/
#Column(name="modifiedCompanyName")
public String getModifiedCompanyName() {
return modifiedCompanyName;
}
public void setModifiedCompanyName(String modifiedCompanyName) {
if(modifiedCompanyName==null)
this.modifiedCompanyName=modifiedCompanyName;
else{
this.modifiedCompanyName =companyDAO.updateCompanyName(modifiedCompanyName);
}
}
#Transient
public List<JobPostingRaw> getUnconfirmedTechnologies() {
return unconfirmedTechnologies;
}
public void setUnconfirmedTechnologies(
List<JobPostingRaw> unconfirmedTechnologies) {
this.unconfirmedTechnologies = unconfirmedTechnologies;
}
}
my DAO class is like that --
package com.salebuild.dao;
import com.salebuild.model.Company;
import com.salebuild.model.search.EntitySearchCriteria;
import com.salebuild.model.search.SortedResultsPage;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public interface CompanyDAO extends CrudDAO<Company> {
Company findByNameOrAlias(String name);
List<Company> findBySearchTerm(String searchTerm, Integer start, Integer count);
// SortedResultsPage<Company> findPaged(EntitySearchCriteria criteria);
List<Long> findIds(EntitySearchCriteria criteria);
List<Company> find(Collection<Long> ids);
/**
* For just finding the company name and not looking for alias names.
*
* #param name
* #return
*/
public Company findByName( String name );
public Company findByModifiedName(String name,Company... c);
public int companyCountSinceLastLogin(Long id);
Set<Long> findDistinctIds(EntitySearchCriteria criteria);
public Integer getCompanyCountByRegion(Long regionId,List techCatIds);
List<Company> findAllCompanies(Company instance);
public List<Company> findAllModifiedCompanies(Company instance);
public String updateCompanyName(String name);
}
The easiest option is to implement factory for building entities. Then you can use AutowireCapableBeanFactory to autowire dependencies:
public abstract class GenericFactory<T> {
#Autowired
private AutowireCapableBeanFactory autowireBeanFactory;
public T createBean() {
// creation logic
autowireBeanFactory.autowireBean(createdBean);
return createdBean;
}
}
Of course you can pass object (created or retrieved) and just autowire it.
Another option is to use #Configurable - it automatically injects dependencies. http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable
You can find more details in my post: http://www.kubrynski.com/2013/09/injecting-spring-dependencies-into-non.html
JPA entities are meant to be POJOs i.e. simple Java beans which do not have dependencies and have getters and setters which contain no complex logic.
It would be better to create a service which is responsible for saving and updating your entity which is used throughout your code. This service can then be responsible for executing the logic you wish to put in your setter using dependencies which can be autowired.
The issue you have is that you Spring is not responsible for the creation of your entity. You either instantiate it using new or you obtain it from your JPA implementation. Either way there is no opportunity for Spring to autowire declared dependencies.
As an aside it's not good practice to autowire private variables. See this blog post for a fuller discussion.

javax.validation getting ignore from jersey

I am trying to use Jersey to get JSON request from the user to create vendor
#POST
#Produces({APPLICATION_JSON})
#Consumes({APPLICATION_JSON})
#Path("create")
public Response create(VendorTO vendorTO) throws Exception {
But before it converts in vendorTO object I want to validate it with javax.validation
I have added constraints in my pojo like this
{#JsonSerialize(include=Inclusion.NON_NULL)
public class VendorTO {
#NotNull
private Integer userId;
#Size(min = 2)
private String vendorName;
private String address1;
private String address2;
private String city;
private String state;
private String country;
private String email;
private String phone;
}
but it doesnt seems to be working. Can anyone help ?
You need to tell the framework that the parameter should be #Validated:
#POST
#Produces({APPLICATION_JSON})
#Consumes({APPLICATION_JSON})
#Path("create")
public Response create(#Valid VendorTO vendorTO) {
// ...
}
At this point, it appears Jersey does not support JSR 303 natively. You might have to write some ResourceFilters and handle the validation manually.

Resources