spring mongodb send only the not null fields - spring

I have an Article document class like.
package com.document.feed.model;
import java.util.List;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.lang.NonNullFields;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
class Source {
private String id;
private String name;
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#ToString
#Document
#Getter
#Setter
#JsonIgnoreProperties(ignoreUnknown = true)
public class Article {
#Id
private String id;
private Source source;
private String author;
private String title;
private String description;
private String url;
private String urlToImage;
private String publishedAt;
private String content;
private String country;
private String category;
// Vector of Tf-Idf weights.
private List<Double> v;
// Extra fields computed during ordering.
private double dot;
// public Article(String id, String author, Double dot) {
// this.id = id;
// this.author = author;
// this.dot = dot;
// }
}
I am using aggregation pipeline to select only author and dot of the documents as:
{
author: 1,
dot: 1
}
Aggregation is done like:
Aggregation aggregation = newAggregation(Article.class,
aggregate("$project",
projection),
sort(Sort.Direction.DESC, "dot")
);
return mongoTemplate.aggregate(aggregation, "article", Article.class);
But I am getting the API response as:
{
"id": "5e137c67771a9880d1639b5d",
"source": null,
"author": "Asian News International",
"title": null,
"description": null,
"url": null,
"urlToImage": null,
"publishedAt": null,
"content": null,
"country": null,
"category": null,
"v": null,
"dot": 3.2454110250954025
},
I want only the non null fields as output. I can do it by defining a new POJO class for the required fields only, but Is there a way to do it without defining new classes(It will be a nightmare if the projection is a parameter of the API only)?

Add jackson annotation #JsonInclude for removing null fields.
#JsonInclude(Include.NON_NULL)

Related

Passing JSON in body spring and constructing object with foreign key

I am trying to create a basic spring API.
I have a Post class that have an attribute User user as foreign key.
package com.example.demo.model;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import jakarta.persistence.*;
import java.util.Objects;
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, updatable = false)
private Long id;
private String title;
private String body;
#ManyToOne
private User user;
public Post() {
}
public Post(String title, String body) {
this.title = title;
this.body = body;
}
// Getters and Settes ...
}
Here is the User class
package com.example.demo.model;
import jakarta.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
#Entity
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, updatable = false)
private Long id;
private String name;
private Integer age;
private String email;
#OneToMany(mappedBy = "user")
private List<Post> posts = new ArrayList<Post>();
#ManyToMany
#JoinTable(name = "user_task",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "task_id"))
private List<Task> tasks = new ArrayList<Task>();
public User() {}
public User(String name, Integer age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
// Getters and Settes ...
}
and here is my Post Controller
package com.example.demo.controller;
import com.example.demo.model.Post;
import com.example.demo.service.PostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping("/post")
public class PostController {
private final PostService postService;
#Autowired
public PostController(PostService postService) {
this.postService = postService;
}
#GetMapping("/all")
public List<Post> getAllPosts (){
System.out.println("3");
return postService.getAllPosts();
}
#GetMapping("/{id}")
public Post getPost(#PathVariable Long id){
System.out.println("2");
return postService.getPost(id);
}
#PostMapping("/create")
public Post createPost(#RequestBody Post post){
return postService.createPost(post);
}
}
So in the /create endpoint i am passing a json object in the body. Here is an exemple:
{
"title": "Post1",
"body": "Post1 Body",
"user": "1"
}
the user: 1 is the foreign key to user who owns the post.
Here is the full error:
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.example.demo.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('1')]
I need to insert the json object into the Post table with the foreign key

Getting null reference on One-to-Many Mapping

I am trying to implement ONE-TO-MANY Mapping in REST but getting null reference of USERDETAILS table in Companies table.
Also added the commented part, when I was using the commented part I was getting expected output while fetching the data through getAllUsers(). But it was creating one extra column don't know how to deal with the same.
Below are the Model classes :
USERDETAILS : :
package com.restapi.user.entity;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Table(name = "USER_DETAIL_INFORMATION")
#Data
#AllArgsConstructor
#NoArgsConstructor
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties(value = {"createdDate","modifyDate"},allowGetters = true)
public class UserDetails {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "user_id_sequence")
#SequenceGenerator(name = "user_id_sequence",sequenceName = "user_Detail_information_Seq")
#JsonProperty(value ="id" )
private Long userId;
#JsonProperty("name")
#Column(name = "user_name")
private String userName;
#JsonProperty("email")
#Column(name = "user_email")
private String userEmail;
#JsonProperty("address")
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_address_id")
#JsonManagedReference
private Address userAddress;
#Column(name ="user_creation_date")
#Temporal(TemporalType.DATE)
#CreatedDate
#JsonProperty("createdDate")
private Date userCreationDate;
#LastModifiedDate
#Temporal(TemporalType.DATE)
#JsonProperty("modifyDate")
#Column(name = "user_modification_date")
private Date modifyDate;
#JsonProperty("companies")
#OneToMany(mappedBy = "userDetailsid",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private List<Companies> companies;
/*#JsonProperty("companies")
#OneToMany(cascade = CascadeType.ALL)
//, mappedBy = "userDetailsid"
#JoinColumn
private List<Companies> companies;
*/
}
Address : :
package com.restapi.user.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "Address_Details")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "address_seq")
#SequenceGenerator(name = "address_seq",sequenceName = "Address_detail_seq")
#Column(name = "ad_id")
private Long addressId;
#JsonProperty(value = "city")
#Column(name = "ad_city")
private String city;
#JsonProperty(value = "state")
#Column(name = "ad_state")
private String state;
#OneToOne(mappedBy ="userAddress")
#JsonBackReference
private UserDetails userDetails;
}
COMPANIES : :
package com.restapi.user.entity;
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.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonProperty;
#Entity
#Table(name = "COMPANY_INFO_DETAILS")
public class Companies {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE,generator = "company_seq")
#SequenceGenerator(name = "company_seq",sequenceName = "Compamy_seq_generator")
private Long companyId;
#JsonProperty("c_code")
#Column(name = "c_code")
private String companyCode;
#JsonProperty("c_name")
#Column(name = "c_name")
private String companyName;
#ManyToOne
#JoinColumn(name = "COMAPNY_user_id")
private UserDetails userDetailsid;
/* #ManyToOne(cascade = CascadeType.ALL)
private UserDetails userDetailsid; */
public Companies() {
super();
// TODO Auto-generated constructor stub
}
public Companies(Long companyId, String companyCode, String companyName, UserDetails userDetails) {
super();
this.companyId = companyId;
this.companyCode = companyCode;
this.companyName = companyName;
this.userDetailsid = userDetails;
}
public Long getCompanyId() {
return companyId;
}
public void setCompanyId(Long companyId) {
this.companyId = companyId;
}
public String getCompanyCode() {
return companyCode;
}
public void setCompanyCode(String companyCode) {
this.companyCode = companyCode;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public UserDetails getUserDetails() {
return userDetailsid;
}
public void setUserDetails(UserDetails userDetails) {
System.out.println("user DETAILD"+userDetails.toString());
this.userDetailsid = userDetails;
}
}
Controller
package com.restapi.user.controller;
import java.util.List;
import java.util.Optional;
import javax.management.loading.PrivateClassLoader;
import javax.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.restapi.user.entity.UserDetails;
import com.restapi.user.exceptionHandling.DataInsertionException;
import com.restapi.user.exceptionHandling.DataNotFoundException;
import com.restapi.user.helper.HelperMethods;
import com.restapi.user.service.UserService;
#RestController
#RequestMapping("/api/user")
public class UserController {
#Autowired
private UserService userService;
#Autowired
private HelperMethods helper;
/***
* This API will save the user Details in the database table.
*
* #return
*/
#PostMapping("/addnewUser")
public ResponseEntity<UserDetails> addNewUser(#RequestBody UserDetails userDetails) {
try {
if (helper.isNullEmpty(userDetails.getUserName())) {
throw new DataInsertionException("UserName is missing from the request- it is a mandatory parameter!!");
} else if (userDetails.getUserAddress()==null) {
throw new DataInsertionException(
"UserAddress is missing from the request- it is a mandatory parameter!!");
} else if (helper.isNullEmpty(userDetails.getUserEmail())) {
throw new DataInsertionException(
"User's Email address is missing from the request- it is a mandatory parameter!!");
} else {
UserDetails details = userService.saveUserDetails(userDetails);
return ResponseEntity.status(HttpStatus.CREATED).body(details);
}
} catch (Exception e) {
throw new DataInsertionException(e.getMessage());
}
}
/***
* This API will fetch the list of users available
*
* #return
* #throws Exception
*/
#GetMapping("/getAllUserDetails")
public ResponseEntity<List<UserDetails>> getListOfUsers() throws Exception {
try {
List<UserDetails> userDetails = userService.getAllUsers();
System.out.println(userDetails.size());
if (userDetails.size() < 1) {
throw new DataNotFoundException("No Data FOUND!!");
} else {
return new ResponseEntity<List<UserDetails>>(userDetails, HttpStatus.OK);
}
} catch (Exception e) {
throw new DataNotFoundException(e.getMessage());
}
}
/***
* This API will fetch the user Details by using the ID
*
* #return
* #throws Exception
*/
#GetMapping("/id/{id}")
public ResponseEntity<UserDetails> getUserById(#PathParam("id") Long id) throws Exception {
try {
Optional<UserDetails> userDetails = userService.getUserById(id);
if (!userDetails.isPresent()) {
throw new DataNotFoundException("No Data FOUND!!");
} else {
return new ResponseEntity<UserDetails>(userDetails.get(), HttpStatus.OK);
}
} catch (Exception e) {
throw new DataNotFoundException(e.getMessage());
}
}
}
REQUEST STRUCTURE ::
{
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"city": "abc",
"state": "JK"
},
"companies": [
{
"c_code": "TCS",
"c_name": "TATA"
},
{
"c_code": "CTS",
"c_name": "COGNI"
}
]
}
RESPONSE_BODY ::
{
"id": 3,
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"addressId": 3,
"city": "abc",
"state": "JK"
},
"createdDate": "2021-05-14T20:13:32.154+00:00",
"modifyDate": "2021-05-14T20:13:32.154+00:00",
"companies": [
{
"companyId": 5,
"userDetails": **null**,
"c_code": "TCS",
"c_name": "TATA"
},
{
"companyId": 6,
"userDetails": **null**,
"c_code": "CTS",
"c_name": "COGNI"
}
]
}
SERVICE CLASS :
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.restapi.user.entity.UserDetails;
import com.restapi.user.repository.UserRepository;
#Service
public class UserService {
#Autowired
private UserRepository repository;
public UserDetails saveUserDetails(UserDetails userDetails) {
return repository.save(userDetails);
}
public List<UserDetails> getAllUsers() {
return repository.findAll();
}
public Optional<UserDetails> getUserById(Long id) {
Optional<UserDetails> user = repository.findById(id);
return user;
}
}
Repository
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.restapi.user.entity.UserDetails;
#Repository
public interface UserRepository extends JpaRepository<UserDetails, Long>{
}
GetRequest result After Commented part
{
"id": 1,
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"addressId": 1,
"city": "abc",
"state": "JK"
},
"createdDate": "2021-05-15",
"modifyDate": "2021-05-15",
"companies": [
{
"companyId": 2,
"userDetails": null,
"c_code": "CTS",
"c_name": "COGNI"
},
{
"companyId": 1,
"userDetails": null,
"c_code": "TCS",
"c_name": "TATA"
}
]
}
]
If not using Commented part
{
"id": 1,
"name": "test_NAME",
"email": "abc#gmail",
"address": {
"addressId": 1,
"city": "abc",
"state": "JK"
},
"createdDate": "2021-05-15",
"modifyDate": "2021-05-15",
"companies": []
}
]
When using Commented part :
When not using commented part :
Expected output should be :
Someone please highlight what I am missing or doing wrong ? Thanks in advance
Thanks for sharing the UserService. Based from your code in saving user details:
public UserDetails saveUserDetails(UserDetails userDetails) {
return repository.save(userDetails);
}
You are not defining any reference between a user and his/her companies. Again, the cascade you did on the UserDetails object will only means that (since you use CascadeType.ALL) once you save the UserDetails object the save operation will also be cascaded to the Company object however, JPA still needs to know the references between these objects, thus you have to set the userDetailsid for each Company object (during construction). Update your service to something like this:
public UserDetails saveUserDetails(UserDetails userDetails) {
userDetails.getCompanies().stream().forEach(company -> company.setUserDetailsid(userDetails));
return repository.save(userDetails);
}
Note: Just remove your commented codes. They would not work anyways without the update of your service as above.
Lastly, I am seeing you are using Lombok here, so why not use it all through out of your classes to remove boilerplates and update the company something like below. I have put #JsonBackReference to avoid infinite recursion of jackson on your response during add new user and create a getter method getUserReferenceId just for you to see the response of company with a reference userId.
#Entity
#Table(name = "COMPANY_INFO_DETAILS")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Companies {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "company_seq")
#SequenceGenerator(name = "company_seq", sequenceName = "Compamy_seq_generator")
private Long companyId;
#JsonProperty("c_code")
#Column(name = "c_code")
private String companyCode;
#JsonProperty("c_name")
#Column(name = "c_name")
private String companyName;
#ManyToOne
#JsonBackReference
#JoinColumn(name = "COMAPNY_user_id")
private UserDetails userDetailsid;
public Long getUserReferenceId() {
return userDetailsid != null ? userDetailsid.getUserId() : null;
}
}

Spring JPA one-to-many relationship return null on update

I have a one-to-many relationship between AcademicYear and subject (One AcademicYear has many Subjects).
Here is the model for AcademicYear:
package com.sms.entity;
import javax.persistence.*;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import org.hibernate.annotations.UpdateTimestamp;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.Date;
import java.util.Set;
#Entity
#Setter
#Getter
#Table(name = "academic_years")
#NoArgsConstructor
#AllArgsConstructor
public class AcademicYear {
public AcademicYear(long id, String name, Date updatedAt) {
this.id = id;
this.name = name;
this.updatedAt = updatedAt;
}
#Schema(description = "Unique identifier of the academic year.", example = "1")
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Schema(description = "Name of the Academic Year.", example = "First Year Primary", required = true)
#Column(name = "name")
private String name;
#JsonManagedReference
#OneToMany(mappedBy="academicYear", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Subject> subjects;
#UpdateTimestamp
#Column(name = "updated_at", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private Date updatedAt;
public Set<Subject> getSubjects() {
return subjects;
}
public void setSubjects(Set<Subject> subjects) {
this.subjects = subjects;
}
}
And the model for Subject:
package com.sms.entity;
import javax.persistence.*;
import com.fasterxml.jackson.annotation.JsonBackReference;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
import java.util.Date;
#Table(name = "subjects")
#Entity
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
public class Subject {
public Subject(long id, String name, Date updatedAt) {
this.id = id;
this.name = name;
this.updatedAt = updatedAt;
}
#Schema(description = "Unique identifier of the subject.", example = "1")
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Schema(description = "name of the subject.", example = "Mathematics-2")
#Column(name = "name")
private String name;
#ManyToOne(cascade = {CascadeType.ALL})
#JsonBackReference
#JoinColumn(name="academic_year_id", nullable=false)
private AcademicYear academicYear;
#UpdateTimestamp
#Column(name = "updated_at", columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private Date updatedAt;
}
When I try to update name attribute for AcademicYear, I send a PUT request with the following body:
{
"id": 2,
"name": "Second Year"
}
I got the following response:
{
"id": 2,
"name": "Second Year",
"subjects": null,
"updatedAt": "2020-03-27T18:01:16.163+0000"
}
I have subjects as null. This AcademicYear entity already have records, when I send GET request with 2 as pathvariable to get the entity I get the following response:
{
"id": 2,
"name": "Second Year",
"subjects": [
{
"id": 3,
"name": "english",
"updatedAt": "2020-03-27T17:39:09.000+0000"
},
{
"id": 4,
"name": "physics",
"updatedAt": "2020-03-26T21:45:09.000+0000"
},
{
"id": 5,
"name": "chemistry",
"updatedAt": "2020-03-26T21:45:09.000+0000"
},
{
"id": 2,
"name": "math",
"updatedAt": "2020-03-27T17:39:09.000+0000"
}
],
"updatedAt": "2020-03-27T18:01:16.000+0000"
}
I have fetch type as EAGER, don't know why I get subjects as null when I update the entity name. Any help?
You need to use PATCH instead of PUT for partial updates.
Here is why
Based on RFC 7231, PUT should be used only for complete replacement of representation, in an idempotent operation. PATCH should be used for partial updates.
Based on your input, request set null to subjects.
If you still want to use the PUT then you need to provide the whole request object which you want to update/replace
you can find more details here
Why isn't HTTP PUT allowed to do partial updates in a REST API?

Get all the collection in document

I have following structure in firebase data
Orders -> OrderID -> LocationHistory -> LocationHistoryID -> FieldsData
Orders and LocationHistory are constant whereas OrderID ,LocationHistoryID are document ID
I want to know if it is possible to generate a query to get all LocationHistory of an order in repository which extends FirestoreReactiveRepository
in rest it whould be /Orders/10002/LocationHistory/
Belwo is the code i am currently using
import org.springframework.cloud.gcp.data.firestore.Document;
import com.google.cloud.firestore.annotation.DocumentId;
import com.google.cloud.firestore.annotation.PropertyName;
import lombok.Getter;
import lombok.Setter;
#Setter
#Getter
#Document(collectionName = "Orders/10002/LocationHistory")
public class LocationHistory
{
#DocumentId
private String id;
private String lat;
#PropertyName("long")
private String longitude;
}
Since LocationHistory is a sub-collection of the Orders, you should retrieve the Order which will contain the LocationHistory.
#Setter
#Getter
#Document(collectionName = "Orders")
public class Order
{
#DocumentId
private String id;
private List<LocationHistory> locationHistory;
}
#Setter
#Getter
public class LocationHistory
{
#DocumentId
private String id;
private String lat;
#PropertyName("long")
private String longitude;
}

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

Resources