Welcome to our JPA hello world tutorial, where we’ll guide you through the basics of Java Persistence API (JPA). Follow along as we demonstrate step-by-step instructions, best practices, and practical examples to ensure you grasp the fundamental concepts of JPA programming. Let’s dive into this comprehensive tutorial and unlock the power of JPA for your next project.
Create the Maven project
Firstly, we need a Maven project for our HelloWorld JPA application. We recommend using the Jakarta EE Starter which allows to generate a Maven project for Jakarta EE 8/9/10 Projects: https://start.jakarta.ee/
Select the Jakarta EE version, the Java version and the Runtime, for example WildFly application Server:
Coding the Entity Class
Firstly, let’s define our Model. We will be using a single Customer Class to map a Database Table.
Here is our Customer Class definition:
@Entity public class Customer implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String email; private String address; @Column(name = "phone_number") private String phoneNumber; // Getter/Setter methods omitted for brevity }
To learn more about different types of Strategies you can use for Primary Keys check this article: Choosing the Strategy for Primary keys in JPA
Coding the Service Class
Next, in order to store our Entity in a transactional way, we a CDI Bean which uses Transactional methods in insert and update operations:
@Model public class CustomerService { private static final Logger LOGGER = Logger.getLogger(CustomerService.class.getName()); @PersistenceContext EntityManager em; @Transactional public void createCustomer(Customer customer) { em.persist(customer); LOGGER.info("Created Customer "+customer); } @Transactional public void updateCustomer( Customer customer ) { Customer customerToUpdate = findCustomerById(customer.getId()); customerToUpdate.setName(customer.getName()); customerToUpdate.setEmail(customer.getEmail()); customerToUpdate.setAddress(customer.getAddress()); customerToUpdate.setPhoneNumber(customer.getPhoneNumber()); LOGGER.info("Updated customer" + customer); } @Transactional public void deleteCustomer(Long customerId) { Customer c = findCustomerById(customerId); em.remove(c); LOGGER.info("Deleted Customer with id" + customerId); } public Customer findCustomerById(Long id) { Customer customer = em.find(Customer.class, id); if (customer == null) { throw new WebApplicationException("Customer with id of " + id + " does not exist.", 404); } return customer; } public List<Customer> findAllCustomers() { Query query = em.createQuery("SELECT c FROM Customer c"); List<Customer> customerList = query.getResultList(); return customerList; } public Customer findCustomerByName(String name) { Query query = em .createQuery("SELECT c FROM Customer c WHERE c.name = :name"); query.setParameter("name", name); Customer customer = (Customer) query.getSingleResult(); return customer; } }
Coding a REST Endpoint for the Service Class
Finally, we need a front-end for our application. To keep it pretty simple, we will add a basic REST Endpoint which maps all the Service methods:
@Path("/customer") @Produces("application/json") @Consumes("application/json") public class CustomerEndpoint { @Inject CustomerService customerService; @POST public Response create(Customer customer) { customerService.createCustomer(customer); return Response.status(201).build(); } @GET public List<Customer> findAllCustomers() { return customerService.findAllCustomers(); } @GET @Path("/{id}") public Customer findCustomerById(@PathParam("id") Long id) { return customerService.findCustomerById(id); } @PUT public Response updateCustomer(Customer customer) { customerService.updateCustomer(customer); return Response.status(204).build(); } @DELETE @Path("/{id}") public Response delete(@PathParam("id") Long id) { customerService.deleteCustomer(id); return Response.status(204).build(); } }
As you can see, the above REST endpoint has some basic methods for creating and querying our Entity objects, returning a JSON view of it. In order to get it working our REST Services, we need a REST Activator class:
@ApplicationPath("/rest") public class RestActivator extends Application { }
Adding the persistence.xml file
Then, we will add a persistence.xml file which binds the Persistence Unit to the default ExampleDS Datasource that is available in WIldFly.
<persistence xmlns="https://jakarta.ee/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_1.xsd" version="3.1"> <persistence-unit name="primary"> <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source> <properties> <!-- AUTO-GENERATED FROM ANNOTATIONS METADATA --> <property name="jakarta.persistence.schema-generation.database.action" value="drop-and-create"/> <property name="jakarta.persistence.schema-generation.create-source" value="metadata"/> <property name="jakarta.persistence.schema-generation.drop-source" value="metadata"/> <property name="hibernate.show_sql" value="true"/> </properties> </persistence-unit> </persistence>
As you can see from the above configuration, we are also adding the properties to allow the generation of the Database schema from the annotations available in the application.
Some sample Data with import.sql
Finally, we will add a resources/import.sql file to insert some sample data at start:
INSERT INTO Customer (name, email, address, phone_number) VALUES ('John Doe', '[email protected]', '123 Main Street', '555-1234') INSERT INTO Customer (name, email, address, phone_number) VALUES ('Jane Smith', '[email protected]','45 Elm Street','34243')
Run and Test the Project
Now compile the project:
$ mvn clean install wildfly:deploy
Then, let’s list all available Customers:
curl -s -X GET http://localhost:8080/jpa-basic/rest/customer | jq [ { "address": "123 Main Street", "email": "[email protected]", "id": 1, "name": "John Doe", "phoneNumber": "555-1234" }, { "address": "45 Elm Street", "email": "[email protected]", "id": 2, "name": "Jane Smith", "phoneNumber": "34243" } ]
To add a new Customer:
curl -X POST -H "Content-Type: application/json" -d '{ "name": "Frank Smith", "email": "[email protected]", "address": "123 Random Street", "phoneNumber": "432-1234" }' http://localhost:8080/jpa-basic/rest/customer
To update an existing Customer:
curl -X PUT -H "Content-Type: application/json" -d '{ "id": {id}, "name": "Updated Name", "email": "[email protected]", "address": "456 Elm Street", "phoneNumber": "555-5678" }' http://localhost:8080/jpa-basic/rest/customer
Finally, to delete a Customer:
curl -X DELETE http://localhost:8080/jpa-basic/rest/customer/{id}
Conclusion
Congratulations on completing this JPA hello world tutorial! You have gained a solid understanding of Java Persistence API and its capabilities for simplifying database operations and improving code maintainability. By following along with our step-by-step instructions and practical examples, you have taken the first step towards becoming proficient in JPA programming. Armed with this knowledge, you can now confidently incorporate JPA into your projects, unlocking its power to streamline data persistence and manipulation. Keep exploring and experimenting with JPA’s advanced features to take your data management to the next level. Happy coding with JPA!
You can find the source code for this JPA application on: https://github.com/fmarchioni/mastertheboss/tree/master/javaee/jpa-basic