Using JPA in an application

So far, we have looked at how to create EJBs and CDI-managed beans and how to inject the beans in classes. We then looked at defining entities, defining relations between entities, and mapping entities to the database tables. Let's now combine all of this information to create a simple application where we will create an identity such as a person object and persist it into the database. Later, we will enhance this module so that it can carry out read, update, and delete operations.

Let's create a simple JPA project using Maven with the following dependencies:

  <dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax.annotation-api}</version>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>javax.ejb-api</artifactId>
<version>${javax.ejb-api}</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${javax.enterprise.cdi.api}</version>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>${hibernate-jpa}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-core}</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>${org.eclipse.persistence.jpa}</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql}</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${mockito-core}</version>
<scope>test</scope>
</dependency>
</dependencies>

Create a beans.xml file under the resources/META-INF directory with bean-discovery-mode set to all, as follows:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>

Add the persistence.xml file, which will have the following database configurations:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
>
<persistence-unit name="prod">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>org.rao.kotlin.service.PersonServiceImpl</class>
<class>org.rao.kotlin.entity.Person</class>
<class>org.rao.kotlin.entity.ContactDetails</class>
<class>org.rao.kotlin.entity.Address</class>
<exclude-unlisted-classes/>
<properties>
<property name="javax.persisteData creatednce.jdbc.driver"
value="org.postgresql.Driver"/>
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost:5432/postgres"/>
<property name="javax.persistence.jdbc.user"
value="postgres"/>
<property name="javax.persistence.jdbc.password"
value="*****"/>
</properties>
</persistence-unit>

</persistence>

Now, let's consider the Person entity that we wrote earlier:

@Table(name = "person")
@Entity
@NamedQuery(name = FIND_ALL_PERSON, query = "select p from Person p")
data class Person(val loginId: String) {
@Id
lateinit var identifier: String
lateinit var name: String

@Enumerated(EnumType.STRING)
var preferredLanguage: PreferredLanguage? = null

@OneToMany(cascade = arrayOf(CascadeType.ALL), fetch =
FetchType.LAZY)
@JoinColumn(name = "PERSON_ID", nullable = false,
referencedColumnName = "identifier")
    lateinit var contact: List<ContactDetails>
@Embedded
lateinit var address: Address
}

Our aim is to create this person entity and insert it into the database. Let's create specific layers in the project setup. We will create dao, service, and entity packages, as demonstrated in the following screenshot:

dao is used to deal with the database and is responsible for persisting the data. The dao layer talks to the database and is responsible for making the data ready for persistence. The entity package includes all the required entities in the project.

First, we will write a unit test case:

  1. We will create a request in the setUp() function and mock the response:
@RunWith(MockitoJUnitRunner::class)
class PersonTest {
@Mock
private lateinit var personDao: PersonDaoImpl
private lateinit var createPersonRequest: Person
private lateinit var createPersonResponse: Person

@Before
fun setUp() {

createPersonRequest = Person("myLoginId" + Random().nextInt())
createPersonRequest.name = "myName"
val contactDetails = ContactDetails()

contactDetails.number = "1234567891"
contactDetails.type = ContactType.WORK
val contactDetailsList = ArrayList<ContactDetails>()
contactDetailsList.add(contactDetails)
createPersonRequest.contact = contactDetailsList

val address = Address()
address.street = "Charles street"
address.city = "Bengaluru"
address.state = "Karnataka"
address.country = "India"
createPersonRequest.address = address

createPersonResponse = Person("testLoginId")
createPersonResponse.identifier = UUID.randomUUID().toString()

}

@Test
fun test() {
Mockito.`when`(personDao.createPerson(createPersonRequest)).thenReturn(createPersonResponse)
createPersonRequest.preferredLanguage = PreferredLanguage.EN_US
val person = personDao.createPerson(createPersonRequest)
Assert.assertNotNull(person.identifier)
}
}

In this test case, we create the request object that needs to be persisted and mock the response for the Person class in the setUp() function. We also mock personDao and, using this, we invoke the createPerson() function by passing the request. We use the Mockito when clause to return the mock response when the call is made to the personDao.createPerson() function, and we assert for a non-null value of the identifier in the mock response.

  1. Let's now implement the dao class. It has a createPerson() function. Create an entity manager for the context that we defined in the persistence.xml file:
@Stateless
class PersonDaoImpl : PersonDao {
@PersistenceContext(unitName = "prod")
private var entityManager: EntityManager = Persistence
.createEntityManagerFactory("prod")
.createEntityManager()

override
fun createPerson(person: Person): Person {
entityManager.transaction.begin()
entityManager.persist(person)
entityManager.transaction.commit()
return person
}
}
  1. Add PersonServiceImpl, which makes the data ready for persisting. It checks for PreferredLanguage and adds a unique ID to the person data:
@Dependent
class PersonServiceImpl : PersonService {
@Inject
private lateinit var personDao: PersonDao

@Inject
private lateinit var defaultPreferredLanguage: PreferredLanguage

override
fun createPerson(createPerson: Person): Person {
var person = createPerson

person.preferredLanguage = if (createPerson.preferredLanguage == null)
defaultPreferredLanguage
else
person.preferredLanguage
person.identifier = UUID.randomUUID().toString()
return personDao.createPerson(person)
}
}
  1. Let's write a class that invokes createPerson in the service class with the createPersonRequest function and actually persists the data in the database. This class is a kind of integration test for the code that we have written so far:
object App {
@Inject
lateinit var personServiceImpl: PersonServiceImpl

@JvmStatic
fun main(args: Array<String>) {

val createPersonRequest = Person("myLoginId" +
Random().nextInt())
val contactDetails = ContactDetails()

contactDetails.number = "1234567871"
contactDetails.type = ContactType.WORK
val contactDetailsList = ArrayList<ContactDetails>()
contactDetailsList.add(contactDetails)
createPersonRequest.contact = contactDetailsList

val address = Address()
address.street = "Avenue Road"
address.city = "Bengaluru"
address.state = "Karnataka"
address.country = "India"

createPersonRequest.address = address
createPersonRequest.name = "myName"
createPersonRequest.preferredLanguage = PreferredLanguage.EN_US
val person =
personServiceImpl.createPerson(createPersonRequest)
println("Data created " + person.identifier)

}
}

In this class, we create a request for the data to be created. We create a createPersonRequest of the Person type. We instantiate this instance with the Person() constructor and populate some of this test data to this instance. We invoke the createPerson() function of the service class and, in response, it gets the person entity that is being created in the database.  

  1. We can see that the data is actually persisted in the person table in the database:

  1. The same person entry is persisted in the contact table that we mapped using the OneToMany relationship:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset