Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions jopa-api/src/main/java/cz/cvut/kbss/jopa/model/EntityManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,17 @@ public interface EntityManager extends AutoCloseable {
*/
<T> EntityGraph<T> createEntityGraph(Class<T> rootType);

/**
* Obtain a named {@link EntityGraph}.
* <p>
* The returned instance of EntityGraph should be considered immutable.
*
* @param graphName Name of an existing entity graph
* @return Named entity graph
* @throws IllegalArgumentException If there is no entity graph with the specified name
*/
EntityGraph<?> getEntityGraph(String graphName);

/**
* Return an object of the specified type to allow access to the provider-specific API. If the provider's
* EntityManager implementation does not support the specified class, the {@link OWLPersistenceException} is
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cz.cvut.kbss.jopa.model.annotations;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* A NamedAttributeNode is a member element of a {@link NamedEntityGraph}.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NamedAttributeNode {

/**
* (Required) The name of the attribute that must be included in the graph.
*/
String value();

/**
* (Optional) If the attribute references a managed type that has its own AttributeNodes, this element is used to
* refer to that {@link NamedSubgraph} definition.
* <p>
* If the target type has inheritance, multiple subgraphs can be specified.These additional subgraphs are intended
* to add subclass-specific attributes. Superclass subgraph entries will be merged into subclass subgraphs.
* <p>
* The value of this element is the name of the subgraph as specified by the name element of the corresponding
* NamedSubgraph element. If multiple subgraphs are specified due to inheritance, they are referenced by this name.
*/
String subgraph() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package cz.cvut.kbss.jopa.model.annotations;

import cz.cvut.kbss.jopa.model.EntityManager;

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Defines a named entity graph.
* <p>
* This annotation must be applied to the root entity of the graph, and specifies the limits of the graph of associated
* attributes and entities fetched when an operation which retrieves an instance or instances of the root entity is
* executed.
* <p>
* A reference to a named entity graph may be obtained by calling {@link EntityManager#getEntityGraph(String)}, and may
* be passed as hint to {@link cz.cvut.kbss.jopa.model.query.TypedQuery}.
*/
@Repeatable(NamedEntityGraphs.class)
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface NamedEntityGraph {

/**
* (Optional) The name used to identify the entity graph in calls to {@link EntityManager#getEntityGraph(String)}.
* <p>
* If no name is explicitly specified, the name defaults to the entity name of the annotated root entity. Entity
* graph names must be unique within the persistence unit.
*/
String name() default "";

/**
* (Optional) A list of attributes of the entity that are included in this graph.
*/
NamedAttributeNode[] attributeNodes() default {};

/**
* (Optional) Includes all the attributes of the annotated entity class as attribute nodes in the
* {@code NamedEntityGraph} without the need to explicitly list them.
* <p>
* Included attributes can still be fully specified by an attribute node referencing a subgraph.
*/
boolean includeAllAttributes() default false;

/**
* (Optional) A list of subgraphs that are included in the entity graph.
* <p>
* These are referenced by name from {@code NamedAttributeNode} definitions.
*/
NamedSubgraph[] subgraphs() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package cz.cvut.kbss.jopa.model.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Used to group {@link NamedEntityGraph} annotations.
*/
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
public @interface NamedEntityGraphs {

NamedEntityGraph[] value();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cz.cvut.kbss.jopa.model.annotations;

/**
* A NamedSubgraph is a member element of a {@link NamedEntityGraph}.
* <p>
* The NamedSubgraph is only referenced from within its containing {@code NamedEntityGraph} and cannot be referenced
* independently. It is referenced by its {@link #name()} from a {@link NamedAttributeNode} element of the
* {@code NamedEntityGraph}.
*/
public @interface NamedSubgraph {

/**
* (Required) The name of the subgraph as referenced from a NamedAttributeNode element.
*/
String name();

/**
* (Required) The list of the attributes of the class that must be included.
* <p>
* If the named subgraph corresponds to a subclass of the class referenced by the corresponding attribute node, then
* only subclass-specific attributes are listed.
*/
NamedAttributeNode[] attributeNodes();

/**
* (Optional) The type represented by this subgraph.
* <p>
* The element must be specified when this subgraph is extending a definition on behalf of a subclass.
*/
Class<?> type() default void.class;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package cz.cvut.kbss.jopa.loaders;

import cz.cvut.kbss.jopa.model.annotations.NamedEntityGraph;
import cz.cvut.kbss.jopa.model.annotations.NamedEntityGraphs;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;

/**
* Manages {@link cz.cvut.kbss.jopa.model.annotations.NamedEntityGraph} instances discovered during classpath
* processing.
* <p>
* The discovered annotations are tracked together with the class on which they were declared, so that the root entity
* type can be later resolved when the entity graph is being built.
*/
public class NamedEntityGraphLoader implements Consumer<Class<?>> {

private final Map<Class<?>, Set<NamedEntityGraph>> graphDeclarations = new HashMap<>();

@Override
public void accept(Class<?> aClass) {
final NamedEntityGraph graphDeclaration = aClass.getDeclaredAnnotation(NamedEntityGraph.class);
if (graphDeclaration != null) {
addDeclaration(aClass, graphDeclaration);
}
final NamedEntityGraphs graphDeclarationSet = aClass.getDeclaredAnnotation(NamedEntityGraphs.class);
if (graphDeclarationSet != null) {
for (NamedEntityGraph g : graphDeclarationSet.value()) {
addDeclaration(aClass, g);
}
}
}

private void addDeclaration(Class<?> aClass, NamedEntityGraph declaration) {
graphDeclarations.computeIfAbsent(aClass, k -> new HashSet<>()).add(declaration);
}

public Map<Class<?>, Set<NamedEntityGraph>> getGraphDeclarations() {
return graphDeclarations;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import cz.cvut.kbss.jopa.exception.MetamodelInitializationException;
import cz.cvut.kbss.jopa.model.JOPAPersistenceProperties;
import cz.cvut.kbss.jopa.model.annotations.NamedEntityGraph;
import cz.cvut.kbss.jopa.model.annotations.SparqlResultSetMapping;
import cz.cvut.kbss.jopa.oom.converter.ConverterWrapper;
import cz.cvut.kbss.jopa.utils.Configuration;
Expand All @@ -39,6 +40,7 @@ public class PersistenceUnitClassFinder {
private final EntityLoader entityLoader = new EntityLoader();
private final ResultSetMappingLoader resultSetMappingLoader = new ResultSetMappingLoader();
private final ConverterLoader converterLoader = new ConverterLoader();
private final NamedEntityGraphLoader namedEntityGraphLoader = new NamedEntityGraphLoader();

private boolean scanned = false;

Expand All @@ -65,6 +67,7 @@ public void scanClasspath(Configuration configuration) {
classpathScanner.addListener(entityLoader);
classpathScanner.addListener(resultSetMappingLoader);
classpathScanner.addListener(converterLoader);
classpathScanner.addListener(namedEntityGraphLoader);
Stream.of(toScan).map(String::trim).forEach(classpathScanner::processClasses);
this.scanned = true;
}
Expand Down Expand Up @@ -100,6 +103,19 @@ public Set<SparqlResultSetMapping> getResultSetMappings() {
return resultSetMappingLoader.getMappings();
}

/**
* Gets {@link NamedEntityGraph}s found during classpath scanning.
* <p>
* The annotations are mapped by the class on which they were declared, so that the root entity type can be later
* resolved when the entity graph is being built.
*
* @return Map of classes to named entity graph annotations declared on them
*/
public Map<Class<?>, Set<NamedEntityGraph>> getNamedEntityGraphs() {
assert scanned;
return namedEntityGraphLoader.getGraphDeclarations();
}

/**
* Gets {@link cz.cvut.kbss.jopa.model.AttributeConverter} implementations found during classpath scanning.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import cz.cvut.kbss.jopa.model.metamodel.Attribute;
import cz.cvut.kbss.jopa.model.metamodel.ManagedType;
import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
import cz.cvut.kbss.jopa.model.metamodel.MetamodelClassMapper;
import cz.cvut.kbss.jopa.model.metamodel.PluralAttribute;

import java.util.ArrayList;
Expand All @@ -15,17 +15,17 @@ public class EntityGraphImpl<T> implements EntityGraph<T>, Subgraph<T> {
private final String name;

private final ManagedType<T> entityType;
private final Metamodel metamodel;
private final MetamodelClassMapper metamodel;

private final Map<String, AttributeNodeImpl<?>> attributeNodes = new HashMap<>();

public EntityGraphImpl(ManagedType<T> entityType, Metamodel metamodel) {
public EntityGraphImpl(ManagedType<T> entityType, MetamodelClassMapper metamodel) {
this.entityType = entityType;
this.metamodel = metamodel;
this.name = null;
}

public EntityGraphImpl(String name, ManagedType<T> entityType, Metamodel metamodel) {
public EntityGraphImpl(String name, ManagedType<T> entityType, MetamodelClassMapper metamodel) {
this.name = name;
this.entityType = entityType;
this.metamodel = metamodel;
Expand Down Expand Up @@ -83,6 +83,10 @@ public List<AttributeNode<?>> getAttributeNodes() {
return new ArrayList<>(attributeNodes.values());
}

AttributeNodeImpl<?> getAttributeNode(String name) {
return attributeNodes.get(name);
}

@Override
public String getName() {
return name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,12 @@ public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
return getCurrentPersistenceContext().createEntityGraph(rootType);
}

@Override
public EntityGraph<?> getEntityGraph(String graphName) {
ensureOpen();
return getCurrentPersistenceContext().getEntityGraph(graphName);
}

@Override
public <T> T unwrap(Class<T> cls) {
ensureOpen();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import cz.cvut.kbss.jopa.model.metamodel.ManagedType;
import cz.cvut.kbss.jopa.model.metamodel.Metamodel;
import cz.cvut.kbss.jopa.model.metamodel.MetamodelBuilder;
import cz.cvut.kbss.jopa.model.metamodel.MetamodelClassMapper;
import cz.cvut.kbss.jopa.model.metamodel.StaticMetamodelInitializer;
import cz.cvut.kbss.jopa.proxy.lazy.gen.LazyLoadingEntityProxyGenerator;
import cz.cvut.kbss.jopa.proxy.reference.EntityReferenceProxyGenerator;
Expand All @@ -47,7 +48,7 @@
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class MetamodelImpl implements Metamodel, MetamodelProvider {
public class MetamodelImpl implements Metamodel, MetamodelProvider, MetamodelClassMapper {

private static final Logger LOG = LoggerFactory.getLogger(MetamodelImpl.class);

Expand All @@ -62,6 +63,7 @@ public class MetamodelImpl implements Metamodel, MetamodelProvider {

private NamedQueryManager namedQueryManager;
private ResultSetMappingManager resultSetMappingManager;
private NamedEntityGraphManager namedEntityGraphManager;

private NamespaceResolver namespaceResolver;

Expand Down Expand Up @@ -95,6 +97,7 @@ public void build(PersistenceUnitClassFinder classFinder) {
initFromMetamodelBuilder(metamodelBuilder);
this.namedQueryManager = metamodelBuilder.getNamedQueryManager();
this.resultSetMappingManager = metamodelBuilder.getResultSetMappingManager();
this.namedEntityGraphManager = metamodelBuilder.getNamedEntityGraphManager();
new StaticMetamodelInitializer(this).initializeStaticMetamodel();
}

Expand Down Expand Up @@ -169,6 +172,10 @@ public ResultSetMappingManager getResultSetMappingManager() {
return resultSetMappingManager;
}

public NamedEntityGraphManager getNamedEntityGraphManager() {
return namedEntityGraphManager;
}

@Override
public Set<URI> getModuleExtractionExtraSignature() {
return Collections.unmodifiableSet(getSignatureInternal());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package cz.cvut.kbss.jopa.model;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
* Manages named {@link EntityGraph}s, which are used to define fetching strategies for entities.
* <p>
* This class is not synchronized because it is expected that modifications are done serially when building the
* persistence unit and all further interactions are read-only.
*/
public class NamedEntityGraphManager {

private final Map<String, EntityGraph<?>> namedEntityGraphs = new HashMap<>();

/**
* Registers the specified {@link EntityGraph} under the specified name.
*
* @param graphName Name of the named entity graph
* @param entityGraph Entity graph to register
* @throws IllegalArgumentException If a named entity graph with the same name already exists
*/
public void addEntityGraph(String graphName, EntityGraph<?> entityGraph) {
Objects.requireNonNull(graphName);
Objects.requireNonNull(entityGraph);
if (namedEntityGraphs.containsKey(graphName)) {
throw new IllegalArgumentException("Entity graph " + graphName + " already exists in this persistence unit.");
}
namedEntityGraphs.put(graphName, entityGraph);
}

/**
* Gets an {@link EntityGraph} with the specified name.
*
* @param graphName Name of entity graph to retrieve
* @return Matching entity graph
* @throws IllegalArgumentException If no such entity graph is found
*/
public EntityGraph<?> getEntityGraph(String graphName) {
if (!namedEntityGraphs.containsKey(graphName)) {
throw new IllegalArgumentException("Entity graph " + graphName + " not found in this persistence unit.");
}
return namedEntityGraphs.get(graphName);
}

/**
* Checks whether this manager contains a graph with the specified name
*
* @param graphName Name to search for
* @return {@code true} if such graph is registered here, {@code false} otherwise
*/
public boolean hasEntityGraph(String graphName) {
return namedEntityGraphs.containsKey(graphName);
}
}
Loading