You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by hw...@apache.org on 2015/12/29 20:25:11 UTC
deltaspike git commit: DELTASPIKE-1052 support entity graphs built
from attribute paths
Repository: deltaspike
Updated Branches:
refs/heads/master 8df71b676 -> 6d75f5ea9
DELTASPIKE-1052 support entity graphs built from attribute paths
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/6d75f5ea
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/6d75f5ea
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/6d75f5ea
Branch: refs/heads/master
Commit: 6d75f5ea95416183964be57275c340f41ab7f82d
Parents: 8df71b6
Author: Harald Wellmann <hw...@apache.org>
Authored: Tue Dec 29 20:25:03 2015 +0100
Committer: Harald Wellmann <hw...@apache.org>
Committed: Tue Dec 29 20:25:03 2015 +0100
----------------------------------------------------------------------
.../data/impl/graph/EntityGraphHelper.java | 139 ++++++++++++++++++-
.../impl/handler/CdiQueryInvocationContext.java | 10 +-
.../deltaspike/data/test/ee7/domain/Flat.java | 21 +++
.../deltaspike/data/test/ee7/domain/House.java | 3 +
.../test/ee7/graph/HouseRepositoryTest.java | 53 ++++++-
.../data/test/ee7/service/HouseRepository.java | 8 ++
6 files changed, 225 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6d75f5ea/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/graph/EntityGraphHelper.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/graph/EntityGraphHelper.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/graph/EntityGraphHelper.java
index 72bad91..eb3b296 100644
--- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/graph/EntityGraphHelper.java
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/graph/EntityGraphHelper.java
@@ -20,6 +20,10 @@ package org.apache.deltaspike.data.impl.graph;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import javax.persistence.EntityManager;
@@ -29,13 +33,42 @@ public final class EntityGraphHelper
{
private static final Class<?> ENTITY_GRAPH_CLASS;
+ private static final Class<?> SUBGRAPH_CLASS;
+ private static final Method ADD_ATTRIBUTE_NODES;
+ private static final Method ADD_SUBGRAPH;
+ private static final Method SUBGRAPH_ADD_ATTRIBUTE_NODES;
static
{
ENTITY_GRAPH_CLASS = ClassUtils.tryToLoadClassForName("javax.persistence.EntityGraph");
+ SUBGRAPH_CLASS = ClassUtils.tryToLoadClassForName("javax.persistence.Subgraph");
+ if (ENTITY_GRAPH_CLASS == null)
+ {
+ ADD_ATTRIBUTE_NODES = null;
+ ADD_SUBGRAPH = null;
+ SUBGRAPH_ADD_ATTRIBUTE_NODES = null;
+ }
+ else
+ {
+ try
+ {
+ ADD_ATTRIBUTE_NODES = ENTITY_GRAPH_CLASS.getMethod("addAttributeNodes",
+ String[].class);
+ ADD_SUBGRAPH = ENTITY_GRAPH_CLASS.getMethod("addSubgraph", String.class);
+ SUBGRAPH_ADD_ATTRIBUTE_NODES = SUBGRAPH_CLASS.getMethod("addAttributeNodes",
+ String[].class);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new EntityGraphException(e.getMessage(), e.getCause());
+ }
+ catch (SecurityException e)
+ {
+ throw new EntityGraphException(e.getMessage(), e.getCause());
+ }
+ }
}
-
-
+
private EntityGraphHelper()
{
// hidden constructor
@@ -72,13 +105,111 @@ public final class EntityGraphHelper
}
}
+ public static Object createEntityGraph(EntityManager em, Class<?> entityClass)
+ {
+ ensureAvailable();
+ try
+ {
+ Method method = EntityManager.class.getMethod("createEntityGraph", Class.class);
+ return method.invoke(em, entityClass);
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new EntityGraphException("no method EntityManager.createEntityGraph()", e);
+ }
+ catch (SecurityException e)
+ {
+ throw new EntityGraphException("no access to method EntityManager.createEntityGraph()",
+ e);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new EntityGraphException("no access to method EntityManager.createEntityGraph()",
+ e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new EntityGraphException(e.getCause().getMessage(), e.getCause());
+ }
+ }
+
private static void ensureAvailable()
{
if (!isAvailable())
{
- throw new EntityGraphException(
- "Class java.persistence.EntityGraph is not available. "
+ throw new EntityGraphException("Class java.persistence.EntityGraph is not available. "
+ "Does your PersistenceProvider support JPA 2.1?");
}
}
+
+ public static Object addSubgraph(Object entityGraph, String attributeName)
+ {
+ try
+ {
+ return ADD_SUBGRAPH.invoke(entityGraph, attributeName);
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new EntityGraphException("no access to method EntityGraph.addSubgraph()", e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new EntityGraphException(e.getCause().getMessage(), e.getCause());
+ }
+ }
+
+ public static void addAttributeNodes(Object graph, String attributeName)
+ {
+ try
+ {
+ if (ENTITY_GRAPH_CLASS.isInstance(graph))
+ {
+ ADD_ATTRIBUTE_NODES.invoke(graph, new Object[] { new String[] { attributeName } });
+ }
+ else if (SUBGRAPH_CLASS.isInstance(graph))
+ {
+ SUBGRAPH_ADD_ATTRIBUTE_NODES.invoke(graph,
+ new Object[] { new String[] { attributeName } });
+ }
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new EntityGraphException("no access to method addAttributeNodes()", e);
+ }
+ catch (InvocationTargetException e)
+ {
+ throw new EntityGraphException(e.getCause().getMessage(), e.getCause());
+ }
+ }
+
+ public static Object buildEntityGraph(EntityManager em, Class<?> entityClass,
+ String[] attributePaths)
+ {
+ Object graph = createEntityGraph(em, entityClass);
+ List<String> paths = new ArrayList<String>(Arrays.asList(attributePaths));
+
+ Collections.sort(paths);
+ Collections.reverse(paths);
+
+ for (String path : attributePaths)
+ {
+ if (path.contains("."))
+ {
+ String[] segments = path.split("\\.");
+ Object parent = addSubgraph(graph, segments[0]);
+
+ for (int i = 1; i < segments.length - 1; i++)
+ {
+ addSubgraph(parent, segments[i]);
+ }
+
+ addAttributeNodes(parent, segments[segments.length - 1]);
+ }
+ else
+ {
+ addAttributeNodes(graph, path);
+ }
+ }
+ return graph;
+ }
}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6d75f5ea/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
index f156741..40686f0 100644
--- a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/handler/CdiQueryInvocationContext.java
@@ -323,7 +323,15 @@ public class CdiQueryInvocationContext implements QueryInvocationContext
}
String graphName = entityGraphAnn.value();
- Object graph = EntityGraphHelper.getEntityGraph(getEntityManager(), graphName);
+ Object graph;
+ if (graphName.isEmpty())
+ {
+ graph = EntityGraphHelper.buildEntityGraph(getEntityManager(), entityClass, entityGraphAnn.paths());
+ }
+ else
+ {
+ graph = EntityGraphHelper.getEntityGraph(getEntityManager(), graphName);
+ }
query.setHint(entityGraphAnn.type().getHintName(), graph);
}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6d75f5ea/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/Flat.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/Flat.java b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/Flat.java
index c961067..e021be3 100644
--- a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/Flat.java
+++ b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/Flat.java
@@ -19,11 +19,16 @@
package org.apache.deltaspike.data.test.ee7.domain;
import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OrderColumn;
import javax.persistence.Table;
@Entity
@@ -36,6 +41,10 @@ public class Flat implements Serializable
@Id
@GeneratedValue
private Long id;
+
+ @OneToMany(mappedBy = "flat", cascade = CascadeType.ALL)
+ @OrderColumn
+ private List<Tenant> tenants = new ArrayList<Tenant>();
@ManyToOne
private House house;
@@ -71,4 +80,16 @@ public class Flat implements Serializable
{
this.house = house;
}
+
+
+ public List<Tenant> getTenants()
+ {
+ return tenants;
+ }
+
+
+ public void setTenants(List<Tenant> tenants)
+ {
+ this.tenants = tenants;
+ }
}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6d75f5ea/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/House.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/House.java b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/House.java
index c8afcfd..a0f7c61 100644
--- a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/House.java
+++ b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/domain/House.java
@@ -30,6 +30,7 @@ import javax.persistence.NamedAttributeNode;
import javax.persistence.NamedEntityGraph;
import javax.persistence.NamedEntityGraphs;
import javax.persistence.OneToMany;
+import javax.persistence.OrderColumn;
import javax.persistence.Table;
@NamedEntityGraphs({
@@ -50,9 +51,11 @@ public class House implements Serializable
private String name;
@OneToMany(mappedBy = "house", cascade = CascadeType.ALL)
+ @OrderColumn
private List<Flat> flats = new ArrayList<Flat>();
@OneToMany(mappedBy = "house", cascade = CascadeType.ALL)
+ @OrderColumn
private List<Garage> garages = new ArrayList<Garage>();
public Long getId()
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6d75f5ea/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/graph/HouseRepositoryTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/graph/HouseRepositoryTest.java b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/graph/HouseRepositoryTest.java
index 8803300..37d619f 100644
--- a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/graph/HouseRepositoryTest.java
+++ b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/graph/HouseRepositoryTest.java
@@ -102,8 +102,6 @@ public class HouseRepositoryTest
{
House house = repository.findOptionalByName("Bellevue");
assertNotNull(house);
- assertNotNull(house.getId());
- assertEquals("Bellevue", house.getName());
PersistenceUnitUtil puu = entityManager.getEntityManagerFactory().getPersistenceUnitUtil();
@@ -117,8 +115,6 @@ public class HouseRepositoryTest
{
House house = repository.fetchByName("Bellevue");
assertNotNull(house);
- assertNotNull(house.getId());
- assertEquals("Bellevue", house.getName());
assertTrue(puu.isLoaded(house, "flats"));
assertFalse(puu.isLoaded(house, "garages"));
@@ -139,6 +135,41 @@ public class HouseRepositoryTest
}
}
+ @Test
+ @InSequence(5)
+ public void should_build_dynamic_graph_from_paths() throws Exception
+ {
+ House house = repository.fetchByNameWithDynamicGraph("Bellevue");
+ assertNotNull(house);
+
+ assertTrue(puu.isLoaded(house, "flats"));
+ assertTrue(puu.isLoaded(house, "garages"));
+
+ assertEquals(2, house.getFlats().size());
+ assertEquals(2, house.getGarages().size());
+
+ Flat flat = house.getFlats().get(0);
+ assertFalse(puu.isLoaded(flat, "tenants"));
+ }
+
+ @Test
+ @InSequence(6)
+ public void should_build_dynamic_graph_from_composite_paths() throws Exception
+ {
+ House house = repository.fetchByNameWithFlatTenants("Bellevue");
+ assertNotNull(house);
+
+ assertTrue(puu.isLoaded(house, "flats"));
+ assertTrue(puu.isLoaded(house, "garages"));
+
+ assertEquals(2, house.getFlats().size());
+ assertEquals(2, house.getGarages().size());
+
+ Flat flat = house.getFlats().get(0);
+ assertTrue(puu.isLoaded(flat, "tenants"));
+ assertEquals(3, flat.getTenants().size());
+ }
+
@Before
public void init() throws Exception
{
@@ -150,6 +181,20 @@ public class HouseRepositoryTest
Flat flat1 = new Flat();
flat1.setName("Flat 1");
flat1.setHouse(house);
+
+ Tenant alice = new Tenant();
+ alice.setName("Alice");
+ alice.setFlat(flat1);
+
+ Tenant bob = new Tenant();
+ bob.setName("Bob");
+ bob.setFlat(flat1);
+
+ Tenant charlie = new Tenant();
+ charlie.setName("Charlie");
+ charlie.setFlat(flat1);
+
+ flat1.setTenants(Arrays.asList(alice, bob, charlie));
Flat flat2 = new Flat();
flat2.setName("Flat 2");
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6d75f5ea/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/service/HouseRepository.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/service/HouseRepository.java b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/service/HouseRepository.java
index f9fa797..e0c6121 100644
--- a/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/service/HouseRepository.java
+++ b/deltaspike/modules/data/test-ee7/src/test/java/org/apache/deltaspike/data/test/ee7/service/HouseRepository.java
@@ -42,6 +42,14 @@ public interface HouseRepository extends FullEntityRepository<House, Long>
@EntityGraph("none")
House fetchByNameWithInvalidGraph(String name);
+ @Query("select h from House h where h.name = ?1")
+ @EntityGraph(paths = {"flats", "garages"})
+ House fetchByNameWithDynamicGraph(String name);
+
+ @Query("select h from House h where h.name = ?1")
+ @EntityGraph(paths = {"flats.tenants", "garages"})
+ House fetchByNameWithFlatTenants(String name);
+
@Modifying @Query("delete from House")
int deleteAll();