package org.javaee7.jpa.entitygraph;
import static org.jboss.shrinkwrap.api.ShrinkWrap.create;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnitUtil;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit.Arquillian;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/**
* In this sample we're going to query a +JPA Entity+ and control property loading by providing +Hints+ using the new
* +JPA Entity Graph+ API.
* <p/>
* Entity Graphs are used in the specification of fetch plans for query or find operations.
*
* <p>
* See: http://radcortez.com/jpa-entity-graphs
*
* @author Roberto Cortez
*/
@RunWith(Arquillian.class)
public class EntityGraphTest {
@PersistenceContext
private EntityManager entityManager;
@Inject
private MovieBean movieBean;
@Deployment
public static WebArchive createDeployment() {
WebArchive war = create(WebArchive.class)
.addPackage("org.javaee7.jpa.entitygraph")
.addAsResource("META-INF/persistence.xml")
.addAsResource("META-INF/create.sql")
.addAsResource("META-INF/drop.sql")
.addAsResource("META-INF/load.sql");
System.out.println("Test war content: \n\n" + war.toString(true) + "\n\n" + "Deploying test archive and starting tests...");
return war;
}
@Before
public void beforeTest() {
// Entity graphs and caches don't quite work together.
entityManager.getEntityManagerFactory().getCache().evictAll();
}
@After
public void afterTest() {
// Entity graphs and caches really don't quite work together.
entityManager.getEntityManagerFactory().getCache().evictAll();
}
@Test
public void testEntityGraphMovieDefault() throws Exception {
PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
List<Movie> listMoviesDefaultFetch = movieBean.listMovies();
for (Movie movie : listMoviesDefaultFetch) {
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
}
@Test
public void testEntityGraphMovieWithActors() throws Exception {
PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
List<Movie> listMoviesWithActorsFetch = movieBean.listMovies("javax.persistence.fetchgraph", "movieWithActors");
for (Movie movie : listMoviesWithActorsFetch) {
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertFalse(movie.getMovieActors().isEmpty());
for (MovieActor movieActor : movie.getMovieActors()) {
assertFalse(persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards"));
}
// https://hibernate.atlassian.net/browse/HHH-8776
// The specification states that by using fetchgraph, attributes should stay unloaded even if defined as
// EAGER (movieDirectors), but specification also states that the persistence provider is allowed to fetch
// additional state.
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors") ||
!persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
List<Movie> listMoviesWithActorsLoad = movieBean.listMovies("javax.persistence.loadgraph", "movieWithActors");
for (Movie movie : listMoviesWithActorsLoad) {
// https://java.net/jira/browse/GLASSFISH-21200
// Glassfish is not processing "javax.persistence.loadgraph".
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertFalse(movie.getMovieActors().isEmpty());
for (MovieActor movieActor : movie.getMovieActors()) {
assertFalse(persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards"));
}
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
}
@Test
public void testEntityGraphMovieWithActorsAndAwards() throws Exception {
PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
List<Movie> listMoviesWithActorsFetch = movieBean.listMovies("javax.persistence.fetchgraph", "movieWithActorsAndAwards");
for (Movie movie : listMoviesWithActorsFetch) {
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertFalse(movie.getMovieActors().isEmpty());
for (MovieActor movieActor : movie.getMovieActors()) {
assertTrue(persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards") ||
!persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards"));
}
// https://hibernate.atlassian.net/browse/HHH-8776
// The specification states that by using fetchgraph, attributes should stay unloaded even if defined as
// EAGER (movieDirectors), but specification also states that the persistence provider is allowed to fetch
// additional state.
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors") ||
!persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
List<Movie> listMoviesWithActorsLoad =
movieBean.listMovies("javax.persistence.loadgraph", "movieWithActorsAndAwards");
for (Movie movie : listMoviesWithActorsLoad) {
// https://java.net/jira/browse/GLASSFISH-21200
// Glassfish is not processing "javax.persistence.loadgraph".
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertFalse(movie.getMovieActors().isEmpty());
for (MovieActor movieActor : movie.getMovieActors()) {
assertTrue(persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards"));
}
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
}
@Test
public void testEntityGraphProgrammatically() throws Exception {
PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
EntityGraph<Movie> fetchAll = entityManager.createEntityGraph(Movie.class);
fetchAll.addSubgraph(Movie_.movieActors);
fetchAll.addSubgraph(Movie_.movieDirectors);
fetchAll.addSubgraph(Movie_.movieAwards);
List<Movie> moviesFetchAll = movieBean.listMovies("javax.persistence.fetchgraph", fetchAll);
for (Movie movie : moviesFetchAll) {
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
}
@Test
public void testEntityGraphWithNamedParameters() throws Exception {
PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
List<Movie> listMovieById = movieBean.listMoviesById(1, "javax.persistence.fetchgraph", "movieWithActors");
assertFalse(listMovieById.isEmpty());
assertEquals(1, listMovieById.size());
for (Movie movie : listMovieById) {
assertTrue(
"The ID of the movie entity should have been 1 but was " + movie.getId(),
movie.getId().equals(1));
assertTrue(
"Attribute movieActors of entity Movie should have been loaded, but was not",
persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertFalse(movie.getMovieActors().isEmpty());
for (MovieActor movieActor : movie.getMovieActors()) {
assertFalse(persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards"));
}
// https://hibernate.atlassian.net/browse/HHH-8776
// The specification states that by using fetchgraph, attributes should stay unloaded even if defined as
// EAGER (movieDirectors), but specification also states that the persistence provider is allowed to fetch
// additional state.
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors") ||
!persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
}
@Test
public void testEntityGraphWithNamedParametersList() throws Exception {
PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
// Hibernate fails mixing Entity Graphs and Named Parameters with "IN". Throws NPE
List<Movie> listMoviesByIds = movieBean.listMoviesByIds(Arrays.asList(1, 2), "javax.persistence.fetchgraph", "movieWithActors");
assertFalse(listMoviesByIds.isEmpty());
assertEquals(2, listMoviesByIds.size());
for (Movie movie : listMoviesByIds) {
assertTrue(movie.getId().equals(1) || movie.getId().equals(2));
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieActors"));
assertFalse(movie.getMovieActors().isEmpty());
for (MovieActor movieActor : movie.getMovieActors()) {
assertFalse(persistenceUnitUtil.isLoaded(movieActor, "movieActorAwards"));
}
// https://hibernate.atlassian.net/browse/HHH-8776
// The specification states that by using fetchgraph, attributes should stay unloaded even if defined as
// EAGER (movieDirectors), but specification also states that the persistence provider is allowed to fetch
// additional state.
assertTrue(persistenceUnitUtil.isLoaded(movie, "movieDirectors") ||
!persistenceUnitUtil.isLoaded(movie, "movieDirectors"));
assertFalse(persistenceUnitUtil.isLoaded(movie, "movieAwards"));
}
}
}