In the context of Java Persistence API (JPA), entity lifecycle events refer to the various points during the existence of an entity when specific operations or events are triggered. JPA provides a set of standard lifecycle events that correspond to different phases in the life of an entity. These events allow developers to execute custom logic or actions in response to certain state transitions of the entity.
Below are all supported events of JPA.
Event
Annotation
Description
PrePersist
@PrePersist
Executed before a new entity is persisted.
PostPersist
@PostPersist
Executed after a new entity has been persisted.
PreRemove
@PreRemove
Executed before an entity is removed from the database.
PostRemove
@PostRemove
Executed after an entity has been removed from the database.
PreUpdate
@PreUpdate
Executed before an entity is updated in the database.
PostUpdate
@PostUpdate
Executed after an entity has been updated in the database.
PostLoad
@PostLoad
Executed after an entity has been loaded into the persistence context.
packagecom.springboot.project.entity;importjakarta.persistence.*;importlombok.Getter;importlombok.Setter;importlombok.extern.slf4j.Slf4j;importjava.util.Date;importjava.util.UUID;@Getter@Setter@Entity@Slf4j@Table(name="customers",indexes={@Index(name="uniqueEmailIndex",columnList="email",unique=true),@Index(name="uniquePhoneIndex",columnList="phone",unique=true),@Index(name="uniqueMultiIndex",columnList="email, phone",unique=true)})publicclassCustomerEntity{@Id@GeneratedValue(strategy=GenerationType.UUID)privateUUIDid;privateStringfullName;privateStringemail;privateStringaddress;privateStringphone;@Enumerated(EnumType.STRING)privateGendergender;privateDatedob;@PrePersistpublicvoidlogNewCustomerAttempt(){log.info("@PrePersist Attempting to add new Customer with username: "+this.fullName);}@PostPersistpublicvoidlogNewCustomerAdded(){log.info("@PostPersist Added Customer '"+this.fullName+"' with ID: "+this.id);}@PreRemovepublicvoidlogCustomerRemovalAttempt(){log.info("@PreRemove Attempting to delete Customer: "+this.fullName);}@PostRemovepublicvoidlogCustomerRemoval(){log.info("@PostRemove Deleted Customer: "+this.fullName);}@PreUpdatepublicvoidlogCustomerUpdateAttempt(){log.info("@PreUpdate Attempting to update Customer: "+this.fullName);}@PostUpdatepublicvoidlogCustomerUpdate(){log.info("@PostUpdate Updated Customer: "+this.fullName);}@PostLoadpublicvoidlogCustomerLoad(){log.info("@PostLoad load customer: "+this.fullName);}}
With the example above we are using the lifecycle event annotations directly in the entity through callback methods. Remember that these methods have to have a void return type.
There is another way to use these annotations is creating an EntityListener with annotated callback methods.
As you can see we will create a CustomerListener and put callback methods with lifecycle annotations above. These callback methods have to have a void return type also.
We can also use two approaches above at the same time in the same entity.
<plugins><plugin><groupId>org.openapitools</groupId><artifactId>openapi-generator-maven-plugin</artifactId><version>7.0.1</version><executions><execution><goals><goal>generate</goal></goals><configuration><!-- path to the openapi file spec `.yml` --><inputSpec>${project.basedir}/src/main/resources/openapi/openapi-server.yml
</inputSpec><generatorName>spring</generatorName><!-- generated package for api interface --><apiPackage>com.springboot.project.generated.api</apiPackage><!-- generated package for models --><modelPackage>com.springboot.project.generated.model</modelPackage><!-- using supportingFilesToGenerate --><supportingFilesToGenerate>ApiUtil.java
</supportingFilesToGenerate><configOptions><useTags>true</useTags><delegatePattern>true</delegatePattern><dateLibrary>java8</dateLibrary><java8>false</java8><interfaceOnly>true</interfaceOnly><useBeanValidation>true</useBeanValidation><performBeanValidation>true</performBeanValidation><useOptional>false</useOptional><useSpringBoot3>true</useSpringBoot3></configOptions></configuration></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version><configuration><source>17</source><target>17</target><annotationProcessorPaths><path><groupId>org.mapstruct</groupId><artifactId>mapstruct-processor</artifactId><version>1.5.5.Final</version></path><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></path><path><groupId>org.projectlombok</groupId><artifactId>lombok-mapstruct-binding</artifactId><version>0.2.0</version></path></annotationProcessorPaths></configuration></plugin></plugins>
Now, in the folder resource, we will create a folder openapi and a openapi-server.yaml inside it. The content of this file will look like below with some apis.
openapi:3.0.3info:title:Swagger Customer - OpenAPI 3.0description:Everything about sample hibernate second level cachetermsOfService:http://swagger.io/terms/contact:email:apiteam@swagger.iolicense:name:Apache 2.0url:http://www.apache.org/licenses/LICENSE-2.0.htmlversion:1.0.11externalDocs:description:Find out more about Swaggerurl:http://swagger.ioservers:-url:https://petstore3.swagger.io/api/v1tags:-name:customerdescription:Everything about your CustomerexternalDocs:description:Find out moreurl:http://swagger.io-name:orderdescription:Everything about your OrderexternalDocs:description:Find out moreurl:http://swagger.iopaths:/v1/customers:get:tags:-customersummary:get an existing customer infodescription:get an existing customer info by EmailoperationId:getCustomerInfoByEmailparameters:-name:emailin:queryrequired:trueschema:type:stringresponses:'200':description:Successful operationcontent:application/json:schema:$ref:'#/components/schemas/CustomerDetail''400':description:Invalid ID supplied'404':description:Pet not found'405':description:Validation exceptionpost:tags:-customersummary:Add a Customer to databasedescription:Add a Customer to databaseoperationId:addCustomerrequestBody:description:Create a Customer to databasecontent:application/json:schema:$ref:'#/components/schemas/CustomerRequest'required:trueresponses:'200':description:Successful operationcontent:application/json:schema:$ref:'#/components/schemas/CustomerDetail''405':description:Invalid input/v1/customers/{customerId}:get:tags:-customersummary:get an existing customer infodescription:get an existing customer info by IdoperationId:getCustomerparameters:-name:customerIdin:pathrequired:trueschema:type:stringformat:uuidresponses:'200':description:Successful operationcontent:application/json:schema:$ref:'#/components/schemas/CustomerDetail''400':description:Invalid ID supplied'404':description:Pet not found'405':description:Validation exceptionput:tags:-customersummary:Update an existing customerdescription:Update an existing customer by IdoperationId:updateCustomerparameters:-name:customerIdin:pathrequired:trueschema:type:stringformat:uuidrequestBody:description:Update an existent customer in the databasecontent:application/json:schema:$ref:'#/components/schemas/CustomerDetail'required:trueresponses:'200':description:Successful operationcontent:application/json:schema:$ref:'#/components/schemas/CustomerDetail''400':description:Invalid ID supplied'404':description:Pet not found'405':description:Validation exceptiondelete:tags:-customersummary:delete an existing customerdescription:delete an existing customer by IdoperationId:deleteCustomerparameters:-name:customerIdin:pathrequired:trueschema:type:stringformat:uuidresponses:'200':description:Successful operation'400':description:Invalid ID supplied'404':description:Pet not found'405':description:Validation exception/v1/customers/action-filter:post:tags:-customersummary:filter customersdescription:filter customersoperationId:filterCustomersrequestBody:description:Update an existent customer in the databasecontent:application/json:schema:$ref:'#/components/schemas/CustomerFilterRequest'required:trueresponses:'200':description:Successful operationcontent:application/json:schema:type:arrayitems:$ref:'#/components/schemas/CustomerDetail''400':description:Invalid ID supplied'404':description:Pet not found'405':description:Validation exceptioncomponents:schemas:CustomerDetail:allOf:-$ref:'#/components/schemas/CustomerRequest'-type:objectproperties:id:type:stringformat:uuidCustomerRequest:type:objectrequired:-email-phoneproperties:fullName:type:stringemail:type:stringaddress:type:stringphone:type:stringgender:type:stringenum:-M-Fdob:type:stringformat:dateCustomerFilterRequest:type:objectproperties:fullName:type:stringemail:type:stringaddress:type:stringphone:type:string
Now, we can use command mvn clean install to build and generate apis and model from openapi-server.yaml.
packagecom.springboot.project.repository;importcom.springboot.project.entity.CustomerEntity;importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.data.jpa.repository.Query;importorg.springframework.data.repository.query.Param;importorg.springframework.stereotype.Repository;importjava.util.List;importjava.util.Optional;importjava.util.UUID;@RepositorypublicinterfaceCustomerRepositoryextendsJpaRepository<CustomerEntity,UUID>{Optional<CustomerEntity>findCustomerByEmail(Stringemail);@Query(value=" SELECT * FROM customers c "+/*1*/" WHERE (:full_name is null or c.full_name = :full_name) "+/*2*/" AND (:email is null or c.email = :email) "+/*3*/" AND (:address is null or c.address = :address) "+/*4*/" AND (:phone is null or c.phone = :phone); ",/*5*/nativeQuery=true)List<CustomerEntity>filterCustomers(@Param("full_name")StringfullName,@Param("email")Stringemail,@Param("address")Stringaddress,@Param("phone")Stringphone);}
As you can see in this Repository we will define a method to filter customers using native query with optional params.
packagecom.springboot.project.service;importcom.springboot.project.entity.CustomerEntity;importcom.springboot.project.mapper.AutoCustomerMapper;importcom.springboot.project.model.Customer;importcom.springboot.project.model.CustomerFilter;importcom.springboot.project.repository.CustomerRepository;importlombok.AllArgsConstructor;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importjava.util.List;importjava.util.Optional;importjava.util.UUID;@Service@AllArgsConstructor(onConstructor=@__(@Autowired))publicclassCustomerService{privatefinalCustomerRepositorycustomerRepository;publicCustomercreateCustomer(Customercustomer){CustomerEntitycustomerEntity=AutoCustomerMapper.MAPPER.mapToCustomerEntity(customer);customerEntity=this.customerRepository.save(customerEntity);returnAutoCustomerMapper.MAPPER.mapToCustomer(customerEntity);}publicCustomergetCustomer(UUIDcustomerId){Optional<CustomerEntity>customerEntity=this.customerRepository.findById(customerId);if(customerEntity.isPresent()){returnAutoCustomerMapper.MAPPER.mapToCustomer(customerEntity.get());}thrownewRuntimeException("Customer Not Found!");}publicList<Customer>filterCustomers(CustomerFiltercustomerFilter){List<CustomerEntity>foundCustomers=this.customerRepository.filterCustomers(customerFilter.getFullName(),customerFilter.getEmail(),customerFilter.getAddress(),customerFilter.getPhone());returnAutoCustomerMapper.MAPPER.mapToCustomers(foundCustomers);}publicCustomerupdateCustomer(UUIDcustomerId,Customercustomer){Optional<CustomerEntity>customerEntity=this.customerRepository.findById(customerId);if(customerEntity.isPresent()){CustomerEntityexistedCustomerEntity=customerEntity.get();CustomerEntityupdateCustomerEntity=AutoCustomerMapper.MAPPER.mapToCustomerEntity(customer);AutoCustomerMapper.MAPPER.updateCustomerEntity(existedCustomerEntity,updateCustomerEntity);existedCustomerEntity=this.customerRepository.save(existedCustomerEntity);returnAutoCustomerMapper.MAPPER.mapToCustomer(existedCustomerEntity);}thrownewRuntimeException("Customer Not Found!");}publicvoiddeleteCustomer(UUIDcustomerId){this.customerRepository.deleteById(customerId);}publicCustomerfindCustomerByEmail(Stringemail){Optional<CustomerEntity>customerEntity=this.customerRepository.findCustomerByEmail(email);if(customerEntity.isPresent()){returnAutoCustomerMapper.MAPPER.mapToCustomer(customerEntity.get());}thrownewRuntimeException("Customer Not Found! with email: "+email);}}