Skip to content

Commit 6783c4a

Browse files
committed
Added JPA test for the new 2.1 feature of dynamically adding named
queries.
1 parent 630cb0f commit 6783c4a

File tree

9 files changed

+353
-0
lines changed

9 files changed

+353
-0
lines changed

jpa/dynamic-named-query/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<groupId>org.javaee7.jpa</groupId>
6+
<artifactId>jpa-samples</artifactId>
7+
<version>1.0-SNAPSHOT</version>
8+
<relativePath>../pom.xml</relativePath>
9+
</parent>
10+
11+
<groupId>org.javaee7.jpa</groupId>
12+
<artifactId>dynamic-named-query</artifactId>
13+
<version>1.0-SNAPSHOT</version>
14+
<packaging>war</packaging>
15+
</project>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.javaee7.jpa.dynamicnamedquery.entity;
2+
3+
import static javax.persistence.GenerationType.IDENTITY;
4+
5+
import javax.persistence.Entity;
6+
import javax.persistence.GeneratedValue;
7+
import javax.persistence.Id;
8+
9+
/**
10+
* A very simple JPA entity that will be used for testing
11+
*
12+
* @author Arjan Tijms
13+
*
14+
*/
15+
@Entity
16+
public class TestEntity {
17+
18+
@Id
19+
@GeneratedValue(strategy = IDENTITY)
20+
private Long id;
21+
private String value;
22+
23+
public Long getId() {
24+
return id;
25+
}
26+
27+
public void setId(Long id) {
28+
this.id = id;
29+
}
30+
31+
public String getValue() {
32+
return value;
33+
}
34+
35+
public void setValue(String value) {
36+
this.value = value;
37+
}
38+
39+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.javaee7.jpa.dynamicnamedquery.entity;
2+
3+
import javax.persistence.metamodel.SingularAttribute;
4+
import javax.persistence.metamodel.StaticMetamodel;
5+
6+
/**
7+
* The meta model of our JPA entity, which we can use to refer to the Entity's attributes
8+
* in a type-safe way (if only Java 8 had also introduced attribute/property references...)
9+
*
10+
* @author Arjan Tijms
11+
*
12+
*/
13+
@StaticMetamodel(TestEntity.class)
14+
public class TestEntity_ {
15+
16+
public static volatile SingularAttribute<TestEntity, Long> id;
17+
public static volatile SingularAttribute<TestEntity, String> value;
18+
19+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package org.javaee7.jpa.dynamicnamedquery.service;
2+
3+
import static org.javaee7.jpa.dynamicnamedquery.service.QueryRepository.Queries.TEST_ENTITY_GET_ALL;
4+
import static org.javaee7.jpa.dynamicnamedquery.service.QueryRepository.Queries.TEST_ENTITY_GET_BY_VALUE;
5+
6+
import javax.annotation.PostConstruct;
7+
import javax.ejb.Singleton;
8+
import javax.ejb.Startup;
9+
import javax.persistence.EntityManager;
10+
import javax.persistence.EntityManagerFactory;
11+
import javax.persistence.PersistenceContext;
12+
import javax.persistence.PersistenceUnit;
13+
import javax.persistence.TypedQuery;
14+
import javax.persistence.criteria.CriteriaBuilder;
15+
import javax.persistence.criteria.CriteriaQuery;
16+
import javax.persistence.criteria.ParameterExpression;
17+
import javax.persistence.criteria.Root;
18+
19+
import org.javaee7.jpa.dynamicnamedquery.entity.TestEntity;
20+
import org.javaee7.jpa.dynamicnamedquery.entity.TestEntity_;
21+
22+
/**
23+
* This bean's init method is called when the AS starts and dynamically creates a number of queries
24+
* and sets them as named queries on the entity manager factory.
25+
* <p>
26+
* Dynamically adding named queries is a new feature in Java EE 7.
27+
*
28+
* @author Arjan Tijms
29+
*
30+
*/
31+
@Singleton
32+
@Startup
33+
public class QueryRepository {
34+
35+
public enum Queries {
36+
TEST_ENTITY_GET_ALL, TEST_ENTITY_GET_BY_VALUE
37+
}
38+
39+
@PersistenceUnit
40+
private EntityManagerFactory entityManagerFactory;
41+
42+
@PersistenceContext
43+
private EntityManager entityManager;
44+
45+
@PostConstruct
46+
public void init() {
47+
48+
// Stores queries that were created via the Criteria API as named queries.
49+
50+
// This is the Criteria alternative for the feature where JPQL queries can
51+
// be placed in orm.xml files or annotations. (but note that JPQL queries can also
52+
// be added here programmatically).
53+
54+
entityManagerFactory.addNamedQuery(TEST_ENTITY_GET_ALL.name(), buildGetAll());
55+
entityManagerFactory.addNamedQuery(TEST_ENTITY_GET_BY_VALUE.name(), buildGetByValue());
56+
}
57+
58+
/**
59+
* Builds a criteria query equal to the JPQL
60+
*
61+
* <code>SELECT _testEntity FROM TestEntity _testEntity</code>
62+
*
63+
*
64+
*/
65+
private TypedQuery<TestEntity> buildGetAll() {
66+
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
67+
68+
CriteriaQuery<TestEntity> criteriaQuery = criteriaBuilder.createQuery(TestEntity.class);
69+
Root<TestEntity> root = criteriaQuery.from(TestEntity.class);
70+
71+
criteriaQuery.select(root);
72+
73+
return entityManager.createQuery(criteriaQuery);
74+
}
75+
76+
/**
77+
* Builds a criteria query equal to the JPQL
78+
*
79+
* <code>SELECT _testEntity FROM TestEntity _testEntity WHERE _testEntity.value :value</code>
80+
*
81+
*
82+
*/
83+
private TypedQuery<TestEntity> buildGetByValue() {
84+
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
85+
86+
CriteriaQuery<TestEntity> criteriaQuery = criteriaBuilder.createQuery(TestEntity.class);
87+
Root<TestEntity> root = criteriaQuery.from(TestEntity.class);
88+
ParameterExpression<String> valueParameter = criteriaBuilder.parameter(String.class, TestEntity_.value.getName());
89+
90+
criteriaQuery.select(root)
91+
.where(
92+
criteriaBuilder.equal(
93+
root.get(TestEntity_.value), valueParameter)
94+
);
95+
96+
return entityManager.createQuery(criteriaQuery);
97+
}
98+
99+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.javaee7.jpa.dynamicnamedquery.service;
2+
3+
import static org.javaee7.jpa.dynamicnamedquery.service.QueryRepository.Queries.TEST_ENTITY_GET_ALL;
4+
import static org.javaee7.jpa.dynamicnamedquery.service.QueryRepository.Queries.TEST_ENTITY_GET_BY_VALUE;
5+
6+
import java.util.List;
7+
8+
import javax.ejb.Stateless;
9+
import javax.persistence.EntityManager;
10+
import javax.persistence.PersistenceContext;
11+
12+
import org.javaee7.jpa.dynamicnamedquery.entity.TestEntity;
13+
import org.javaee7.jpa.dynamicnamedquery.entity.TestEntity_;
14+
15+
/**
16+
*
17+
* @author Arjan Tijms
18+
*
19+
*/
20+
@Stateless
21+
public class TestService {
22+
23+
@PersistenceContext
24+
private EntityManager entityManager;
25+
26+
public void save(TestEntity testEntity) {
27+
entityManager.persist(testEntity);
28+
}
29+
30+
/**
31+
* Gets a list of all instances of {@link TestEntity} that were persisted
32+
*
33+
* @return a list of all instances of {@link TestEntity} that were persisted
34+
*/
35+
public List<TestEntity> getAll() {
36+
return entityManager.createNamedQuery(TEST_ENTITY_GET_ALL.name(), TestEntity.class).getResultList();
37+
}
38+
39+
/**
40+
* Gets a list of instances of {@link TestEntity} where the <code>value</code> attribute equals
41+
* the <code>value</code> parameter of this method.
42+
*
43+
* @param value the value by which {@link TestEntity} instances are retrieved.
44+
* @return list of {@link TestEntity} instances matching <code>value</code>
45+
*/
46+
public List<TestEntity> getByValue(String value) {
47+
return entityManager.createNamedQuery(TEST_ENTITY_GET_BY_VALUE.name(), TestEntity.class)
48+
.setParameter(TestEntity_.value.getName(), value).getResultList();
49+
}
50+
51+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.javaee7.jpa.dynamicnamedquery.servlet;
2+
3+
import java.io.IOException;
4+
5+
import javax.inject.Inject;
6+
import javax.servlet.ServletException;
7+
import javax.servlet.annotation.WebServlet;
8+
import javax.servlet.http.HttpServlet;
9+
import javax.servlet.http.HttpServletRequest;
10+
import javax.servlet.http.HttpServletResponse;
11+
12+
import org.javaee7.jpa.dynamicnamedquery.entity.TestEntity;
13+
import org.javaee7.jpa.dynamicnamedquery.service.TestService;
14+
15+
/**
16+
* This servlet is not part of the normal test flow, but is an extra artifact to use when deploying the WAR created by this
17+
* Maven project standalone.
18+
*
19+
* @author Arjan Tijms
20+
*
21+
*/
22+
@WebServlet("/servlet")
23+
public class Servlet extends HttpServlet {
24+
25+
private static final long serialVersionUID = 1L;
26+
27+
@Inject
28+
private TestService testService;
29+
30+
@Override
31+
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
32+
33+
TestEntity testEntity = new TestEntity();
34+
testEntity.setValue("myValue");
35+
testService.save(testEntity);
36+
37+
response.getWriter().write("#Entities after insert = " + testService.getAll().size() + "\n");
38+
response.getWriter().write("Value found = " + (testService.getByValue("myValue").size() > 0));
39+
}
40+
41+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
4+
5+
<!--
6+
This defines the persistence unit from which the entity manager is used in org.javaee7.jpa.dynamicnamedquery.service.TestService
7+
8+
Note that this relies on the defaults; in Java EE the transaction type defaults to JTA and the data source defaults to the
9+
platform default data source (which is a new feature in Java EE 7)
10+
11+
-->
12+
13+
<persistence-unit name="testPU" >
14+
<properties>
15+
<property name="javax.persistence.schema-generation.database.action" value="drop-and-create" />
16+
</properties>
17+
</persistence-unit>
18+
</persistence>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<%@page contentType="text/html" pageEncoding="UTF-8"%>
2+
<!DOCTYPE html>
3+
4+
<html>
5+
<head>
6+
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
7+
<title>JPA 2.1 Dynamically adding named queries</title>
8+
</head>
9+
<body>
10+
<h1>JPA 2.1 Dynamically adding named queries</h1>
11+
<a href="${pageContext.request.contextPath}/servlet"/>Using dynamically added criteria queries</a>.
12+
</body>
13+
</html>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package org.javaee7.jpa.dynamicnamedquery;
2+
3+
import static org.junit.Assert.assertTrue;
4+
5+
import java.io.IOException;
6+
7+
import javax.inject.Inject;
8+
9+
import org.javaee7.jpa.dynamicnamedquery.entity.TestEntity;
10+
import org.javaee7.jpa.dynamicnamedquery.service.TestService;
11+
import org.jboss.arquillian.container.test.api.Deployment;
12+
import org.jboss.arquillian.junit.Arquillian;
13+
import org.jboss.shrinkwrap.api.ShrinkWrap;
14+
import org.jboss.shrinkwrap.api.spec.WebArchive;
15+
import org.junit.Test;
16+
import org.junit.runner.RunWith;
17+
import org.xml.sax.SAXException;
18+
19+
/**
20+
* This tests that queries which have been dynamically (programmatically) added as named queries
21+
* can be executed correctly.
22+
*
23+
* @author Arjan Tijms
24+
*
25+
*/
26+
@RunWith(Arquillian.class)
27+
public class DynamicNamedQueryTest {
28+
29+
@Inject
30+
private TestService testService;
31+
32+
@Deployment
33+
public static WebArchive createDeployment() {
34+
return ShrinkWrap.create(WebArchive.class).addPackages(true, "org.javaee7.jpa.dynamicnamedquery")
35+
.addAsResource("META-INF/persistence.xml");
36+
}
37+
38+
@Test
39+
public void testDynamicNamedCriteriaQueries() throws IOException, SAXException {
40+
41+
// Nothing inserted yet, data base should not contain any entities
42+
// (this tests that a simple query without parameters works as named query created by Criteria)
43+
assertTrue(testService.getAll().size() == 0);
44+
45+
// Insert one entity
46+
TestEntity testEntity = new TestEntity();
47+
testEntity.setValue("myValue");
48+
testService.save(testEntity);
49+
50+
// The total amount of entities should be 1
51+
assertTrue(testService.getAll().size() == 1);
52+
53+
// The entity with "myValue" should be found
54+
// (this tests that a query with a parameter works as named query created by Criteria)
55+
assertTrue(testService.getByValue("myValue").size() == 1);
56+
}
57+
58+
}

0 commit comments

Comments
 (0)