Graphpocalypse: actually let's just deprecate the makeXxxxSubGraph() operations...

... and delete the new ones I added.

The reasoning here is that they just aren't properly typesafe,
as you can see by the hoops I had to go through to actually
implement them. And since the whole package is marked
@Incubating, we're not committed to them.

This lets me make the implementation even more typesafe and
detect more user errors and bugs.
This commit is contained in:
Gavin King 2025-01-03 01:28:53 +01:00
parent ced58cc998
commit cfe4346ef8
17 changed files with 404 additions and 301 deletions

View File

@ -6,8 +6,6 @@ package org.hibernate.graph;
import jakarta.persistence.Subgraph;
import jakarta.persistence.metamodel.ManagedType;
import org.hibernate.Incubating;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import java.util.Map;
@ -38,6 +36,8 @@ import static java.util.Collections.unmodifiableMap;
* @apiNote Historically, this interface declared operations with incorrect generic types,
* leading to unsound code. This was in Hibernate 7, with possible breakage to older code.
*
* @param <J> The type of the {@linkplain #getAttributeDescriptor attribute}
*
* @author Strong Liu
* @author Steve Ebersole
* @author Andrea Boriero
@ -99,23 +99,27 @@ public interface AttributeNode<J> extends GraphNode<J>, jakarta.persistence.Attr
/**
* Create and return a new value {@link SubGraph} rooted at this node,
* or return an existing such {@link SubGraph} if there is one.
* <p>
*
* @deprecated This operation is not properly type safe.
* Note that {@code graph.addAttributeNode(att).makeSubGraph()} is a
* synonym for {@code graph.addSubgraph(att)}.
*
* @see Graph#addSubgraph(jakarta.persistence.metamodel.Attribute)
*/
@Deprecated(since = "7.0")
SubGraph<?> makeSubGraph();
/**
* Create and return a new key {@link SubGraph} rooted at this node,
* or return an existing such {@link SubGraph} if there is one.
* <p>
*
* @deprecated This operation is not properly type safe.
* Note that {@code graph.addAttributeNode(att).makeKeySubGraph()} is a
* synonym for {@code graph.addMapKeySubgraph(att)}.
*
* @see Graph#addMapKeySubgraph(jakarta.persistence.metamodel.MapAttribute)
*/
@Deprecated(since = "7.0")
SubGraph<?> makeKeySubGraph();
/**
@ -125,7 +129,8 @@ public interface AttributeNode<J> extends GraphNode<J>, jakarta.persistence.Attr
* <p>
* If the given type is a proper subtype of the value type, the result
* is a treated subgraph.
* <p>
*
* @deprecated This operation is not properly type safe.
* Note that {@code graph.addAttributeNode(att).makeSubGraph(cl)}
* is a synonym for {@code graph.addTreatedSubgraph(att,cl)}.
*
@ -133,6 +138,7 @@ public interface AttributeNode<J> extends GraphNode<J>, jakarta.persistence.Attr
*
* @see Graph#addTreatedSubgraph(jakarta.persistence.metamodel.Attribute, Class)
*/
@Deprecated(since = "7.0")
<S> SubGraph<S> makeSubGraph(Class<S> subtype);
/**
@ -142,7 +148,8 @@ public interface AttributeNode<J> extends GraphNode<J>, jakarta.persistence.Attr
* <p>
* If the given type is a proper subtype of the key type, the result
* is a treated subgraph.
* <p>
*
* @deprecated This operation is not properly type safe.
* Note that {@code graph.addAttributeNode(att).makeKeySubGraph(cl)}
* is a synonym for {@code graph.addTreatedMapKeySubgraph(att,cl)}.
*
@ -150,35 +157,6 @@ public interface AttributeNode<J> extends GraphNode<J>, jakarta.persistence.Attr
*
* @see Graph#addTreatedMapKeySubgraph(jakarta.persistence.metamodel.MapAttribute,Class)
*/
@Deprecated(since = "7.0")
<S> SubGraph<S> makeKeySubGraph(Class<S> subtype);
/**
* Create and return a new value {@link SubGraph} rooted at this node,
* with the given type, which may be a subtype of the value type,
* or return an existing such {@link SubGraph} if there is one.
* <p>
* If the given type is a proper subtype of the value type, the result
* is a treated subgraph.
*
* @param subtype The type or treated type of the value type
*
* @since 7.0
*/
@Incubating
<S> SubGraph<S> makeSubGraph(ManagedType<S> subtype);
/**
* Create and return a new value {@link SubGraph} rooted at this node,
* with the given type, which may be a subtype of the key type,
* or return an existing such {@link SubGraph} if there is one.
* <p>
* If the given type is a proper subtype of the key type, the result
* is a treated subgraph.
*
* @param subtype The type or treated type of the key type
*
* @since 7.0
*/
@Incubating
<S> SubGraph<S> makeKeySubGraph(ManagedType<S> subtype);
}

View File

@ -176,9 +176,7 @@ public interface Graph<J> extends GraphNode<J>, jakarta.persistence.Graph<J> {
* @param attributeName The name of an attribute of the represented type
*/
@Override
default <X> SubGraph<X> addSubgraph(String attributeName) {
return addSubGraph( attributeName );
}
<X> SubGraph<X> addSubgraph(String attributeName);
/**
* Create and return a new (mutable) {@link SubGraph} associated with

View File

@ -4,18 +4,25 @@
*/
package org.hibernate.graph.internal;
import jakarta.persistence.metamodel.ManagedType;
import jakarta.persistence.metamodel.Attribute;
import org.hibernate.graph.CannotContainSubGraphException;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.SubGraphImplementor;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import java.util.HashMap;
import java.util.Map;
import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.EMBEDDED;
import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.MANY_TO_MANY;
import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.MANY_TO_ONE;
import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.ONE_TO_MANY;
import static jakarta.persistence.metamodel.Attribute.PersistentAttributeType.ONE_TO_ONE;
import static java.util.Collections.emptyMap;
@ -25,30 +32,38 @@ import static java.util.Collections.emptyMap;
* @author Steve Ebersole
* @author Gavin King
*/
public class AttributeNodeImpl<J,V,K>
public class AttributeNodeImpl<J, E, K>
extends AbstractGraphNode<J>
implements AttributeNodeImplementor<J> {
implements AttributeNodeImplementor<J, E, K> {
private final PersistentAttribute<?, J> attribute;
private final DomainType<V> valueGraphType;
private final DomainType<E> valueGraphType;
private final SimpleDomainType<K> keyGraphType;
private SubGraphImplementor<V> valueSubgraph;
private SubGraphImplementor<E> valueSubgraph;
private SubGraphImplementor<K> keySubgraph;
static <X,J> AttributeNodeImpl<J,?,?> create(PersistentAttribute<X, J> attribute, boolean mutable) {
return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() );
}
static <X,J,E> AttributeNodeImpl<J,E,?> create(PluralPersistentAttribute<X, J, E> attribute, boolean mutable) {
return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() );
}
static <X,K,V> AttributeNodeImpl<Map<K,V>,V,K> create(MapPersistentAttribute<X, K, V> attribute, boolean mutable) {
return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() );
}
private <X> AttributeNodeImpl(
PersistentAttribute<X, J> attribute, boolean mutable,
DomainType<V> valueGraphType, SimpleDomainType<K> keyGraphType) {
DomainType<E> valueGraphType, SimpleDomainType<K> keyGraphType) {
super( mutable );
this.attribute = attribute;
this.valueGraphType = valueGraphType;
this.keyGraphType = keyGraphType;
}
private AttributeNodeImpl(AttributeNodeImpl<J,V,K> that, boolean mutable) {
private AttributeNodeImpl(AttributeNodeImpl<J, E,K> that, boolean mutable) {
super( mutable );
attribute = that.attribute;
valueGraphType = that.valueGraphType;
@ -68,18 +83,8 @@ public class AttributeNodeImpl<J,V,K>
}
@Override
public SubGraphImplementor<V> getSubGraph() {
return valueSubgraph;
}
@Override
public SubGraphImplementor<K> getKeySubGraph() {
return keySubgraph;
}
@Override
public SubGraphImplementor<V> makeSubGraph() {
verifyMutability();
public SubGraphImplementor<E> addValueSubgraph() {
// this one is intentionally lenient and disfavored
if ( valueSubgraph == null ) {
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
}
@ -87,33 +92,72 @@ public class AttributeNodeImpl<J,V,K>
}
@Override
public SubGraphImplementor<J> addSingularSubgraph() {
checkToOne();
if ( valueSubgraph == null ) {
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
}
// Safe cast, in this case E = J
// TODO: would be more elegant to separate singularSubgraph vs elementSubgraph fields
//noinspection unchecked
return (SubGraphImplementor<J>) valueSubgraph;
}
@Override
public SubGraphImplementor<E> addElementSubgraph() {
checkToMany();
if ( valueSubgraph == null ) {
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
}
return valueSubgraph;
}
@Override
public SubGraphImplementor<K> addKeySubgraph() {
checkMap();
if ( keySubgraph == null ) {
keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true );
}
return keySubgraph;
}
private void checkToOne() {
final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType();
if ( attributeType != MANY_TO_ONE && attributeType != ONE_TO_ONE && attributeType != EMBEDDED ) {
throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-one association" );
}
}
private void checkToMany() {
final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType();
if ( attributeType != MANY_TO_MANY && attributeType != ONE_TO_MANY ) {
throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-many association" );
}
}
@Override @Deprecated
public SubGraphImplementor<E> makeSubGraph() {
verifyMutability();
if ( valueSubgraph == null ) {
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
}
return valueSubgraph;
}
@Override @Deprecated
public <S> SubGraphImplementor<S> makeSubGraph(Class<S> subtype) {
final ManagedDomainType<V> managedType = asManagedType( valueGraphType );
final ManagedDomainType<E> managedType = asManagedType( valueGraphType );
if ( !managedType.getBindableJavaType().isAssignableFrom( subtype ) ) {
throw new IllegalArgumentException( "Not a subtype: " + subtype.getName() );
}
@SuppressWarnings("unchecked")
final Class<? extends V> castSuptype = (Class<? extends V>) subtype;
final SubGraphImplementor<? extends V> result = makeSubGraph().addTreatedSubgraph( castSuptype );
final Class<? extends E> castSuptype = (Class<? extends E>) subtype;
final SubGraphImplementor<? extends E> result = makeSubGraph().addTreatedSubgraph( castSuptype );
//noinspection unchecked
return (SubGraphImplementor<S>) result;
}
@Override
public <S> SubGraphImplementor<S> makeSubGraph(ManagedType<S> subtype) {
final ManagedDomainType<V> managedType = asManagedType( valueGraphType );
final Class<S> javaType = subtype.getJavaType();
if ( !managedType.getBindableJavaType().isAssignableFrom( javaType ) ) {
throw new IllegalArgumentException( "Not a subtype: " + javaType.getName() );
}
@SuppressWarnings("unchecked")
final ManagedDomainType<? extends V> castType = (ManagedDomainType<? extends V>) subtype;
final SubGraphImplementor<? extends V> result = makeSubGraph().addTreatedSubgraph( castType );
//noinspection unchecked
return (SubGraphImplementor<S>) result;
}
@Override
@Override @Deprecated
public SubGraphImplementor<K> makeKeySubGraph() {
verifyMutability();
checkMap();
@ -123,7 +167,7 @@ public class AttributeNodeImpl<J,V,K>
return keySubgraph;
}
@Override
@Override @Deprecated
public <S> SubGraphImplementor<S> makeKeySubGraph(Class<S> subtype) {
checkMap();
final ManagedDomainType<K> type = asManagedType( keyGraphType );
@ -137,21 +181,6 @@ public class AttributeNodeImpl<J,V,K>
return (SubGraphImplementor<S>) result;
}
@Override
public <S> SubGraphImplementor<S> makeKeySubGraph(ManagedType<S> subtype) {
checkMap();
final ManagedDomainType<K> type = asManagedType( keyGraphType );
final Class<S> javaType = subtype.getJavaType();
if ( !type.getBindableJavaType().isAssignableFrom( javaType ) ) {
throw new IllegalArgumentException( "Not a key subtype: " + javaType.getName() );
}
@SuppressWarnings("unchecked")
final ManagedDomainType<? extends K> castType = (ManagedDomainType<? extends K>) subtype;
final SubGraphImplementor<? extends K> result = makeKeySubGraph().addTreatedSubgraph( castType );
//noinspection unchecked
return (SubGraphImplementor<S>) result;
}
private void checkMap() {
if ( keyGraphType == null ) {
throw new CannotContainSubGraphException( "Attribute '" + description() + "' is not a Map" );
@ -179,16 +208,16 @@ public class AttributeNodeImpl<J,V,K>
}
@Override
public AttributeNodeImplementor<J> makeCopy(boolean mutable) {
public AttributeNodeImplementor<J, E, K> makeCopy(boolean mutable) {
return !mutable && !isMutable() ? this : new AttributeNodeImpl<>( this, mutable );
}
@Override
public void merge(AttributeNodeImplementor<J> other) {
public void merge(AttributeNodeImplementor<J, E, K> other) {
assert other.isMutable() == isMutable();
assert other.getAttributeDescriptor() == attribute;
final AttributeNodeImpl<J, V, K> that = (AttributeNodeImpl<J, V, K>) other;
final SubGraphImplementor<V> otherValueSubgraph = that.valueSubgraph;
final AttributeNodeImpl<J, E, K> that = (AttributeNodeImpl<J, E, K>) other;
final SubGraphImplementor<E> otherValueSubgraph = that.valueSubgraph;
if ( otherValueSubgraph != null ) {
if ( valueSubgraph == null ) {
valueSubgraph = otherValueSubgraph.makeCopy( isMutable() );
@ -216,7 +245,7 @@ public class AttributeNodeImpl<J,V,K>
return emptyMap();
}
else {
final HashMap<Class<?>, SubGraphImplementor<?>> map = new HashMap<>( valueSubgraph.getSubGraphs() );
final HashMap<Class<?>, SubGraphImplementor<?>> map = new HashMap<>( valueSubgraph.getTreatedSubgraphs() );
map.put( attribute.getValueGraphType().getBindableJavaType(), valueSubgraph );
return map;
}
@ -228,7 +257,7 @@ public class AttributeNodeImpl<J,V,K>
return emptyMap();
}
else {
final HashMap<Class<?>, SubGraphImplementor<?>> map = new HashMap<>( keySubgraph.getSubGraphs() );
final HashMap<Class<?>, SubGraphImplementor<?>> map = new HashMap<>( keySubgraph.getTreatedSubgraphs() );
map.put( attribute.getKeyGraphType().getJavaType(), keySubgraph );
return map;
}

View File

@ -22,6 +22,7 @@ import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphImplementor;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.graph.spi.SubGraphImplementor;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
@ -41,28 +42,28 @@ import static java.util.Collections.unmodifiableMap;
* @author Steve Ebersole
* @author Gavin King
*/
public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements GraphImplementor<J> {
public abstract class GraphImpl<J> extends AbstractGraphNode<J> implements GraphImplementor<J> {
private final ManagedDomainType<J> managedType;
private Map<Class<? extends J>, SubGraphImplementor<? extends J>> treatedSubgraphs;
private Map<PersistentAttribute<? super J,?>, AttributeNodeImplementor<?>> attributeNodes;
private Map<PersistentAttribute<? super J,?>, AttributeNodeImplementor<?,?,?>> attributeNodes;
public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) {
public GraphImpl(ManagedDomainType<J> managedType, boolean mutable) {
super( mutable );
this.managedType = managedType;
}
protected AbstractGraph(ManagedDomainType<J> managedType, GraphImplementor<J> graph, boolean mutable) {
protected GraphImpl(ManagedDomainType<J> managedType, GraphImplementor<J> graph, boolean mutable) {
super( mutable );
this.managedType = managedType;
var attributeNodesByAttribute = graph.getNodes();
var subGraphMap = graph.getSubGraphs();
var subGraphMap = graph.getTreatedSubgraphs();
attributeNodes = attributeNodesByAttribute.isEmpty() ? null : new HashMap<>( attributeNodesByAttribute.size() );
treatedSubgraphs = subGraphMap.isEmpty() ? null : new HashMap<>( subGraphMap.size() );
mergeInternal( graph );
}
protected AbstractGraph(GraphImplementor<J> graph, boolean mutable) {
protected GraphImpl(GraphImplementor<J> graph, boolean mutable) {
this( graph.getGraphedType(), graph, mutable );
}
@ -77,8 +78,18 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
@SuppressWarnings("unchecked")
private <T> AttributeNodeImplementor<T> getNode(PersistentAttribute<?, ? extends T> attribute) {
return attributeNodes == null ? null : (AttributeNodeImplementor<T>) attributeNodes.get( attribute );
private <T> AttributeNodeImplementor<T,?,?> getNode(PersistentAttribute<?, ? extends T> attribute) {
return attributeNodes == null ? null : (AttributeNodeImplementor<T,?,?>) attributeNodes.get( attribute );
}
@SuppressWarnings("unchecked")
private <T, E> AttributeNodeImplementor<T,E,?> getNode(PluralPersistentAttribute<?, T, E> attribute) {
return attributeNodes == null ? null : (AttributeNodeImplementor<T,E,?>) attributeNodes.get( attribute );
}
@SuppressWarnings("unchecked")
private <K, V> AttributeNodeImplementor<Map<K,V>, V, K> getNode(MapPersistentAttribute<?, K, V> attribute) {
return attributeNodes == null ? null : (AttributeNodeImplementor<Map<K,V>, V, K>) attributeNodes.get( attribute );
}
private <S extends J> SubGraphImplementor<S> getTreatedSubgraphForPut(Class<S> javaType) {
@ -91,7 +102,27 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
}
private <AJ> AttributeNodeImplementor<AJ> getNodeForPut(PersistentAttribute<?, AJ> attribute) {
private <AJ> AttributeNodeImplementor<AJ,?,?> getNodeForPut(PersistentAttribute<?, AJ> attribute) {
if ( attributeNodes == null ) {
attributeNodes = new HashMap<>();
return null;
}
else {
return getNode( attribute );
}
}
private <C, E> AttributeNodeImplementor<C,E,?> getNodeForPut(PluralPersistentAttribute<?, C, E> attribute) {
if ( attributeNodes == null ) {
attributeNodes = new HashMap<>();
return null;
}
else {
return getNode( attribute );
}
}
private <V, K> AttributeNodeImplementor<Map<K,V>, V, K> getNodeForPut(MapPersistentAttribute<?, K, V> attribute) {
if ( attributeNodes == null ) {
attributeNodes = new HashMap<>();
return null;
@ -124,11 +155,11 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
public void mergeInternal(GraphImplementor<J> graph) {
// skip verifyMutability()
graph.getNodes().forEach( this::mergeNode );
graph.getSubGraphs().values().forEach( this::mergeGraph );
graph.getTreatedSubgraphs().values().forEach( this::mergeGraph );
}
private void mergeNode(PersistentAttribute<? super J, ?> attribute, AttributeNodeImplementor<?> node) {
final AttributeNodeImplementor<?> existingNode = getNodeForPut( attribute );
private void mergeNode(PersistentAttribute<? super J, ?> attribute, AttributeNodeImplementor<?,?,?> node) {
final AttributeNodeImplementor<?,?,?> existingNode = getNodeForPut( attribute );
if ( existingNode == null ) {
attributeNodes.put( attribute, node.makeCopy( isMutable() ) );
}
@ -150,11 +181,11 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
}
private static <T> void mergeNode(
AttributeNodeImplementor<?> node, AttributeNodeImplementor<T> existingNode) {
private static <T,E,K> void mergeNode(
AttributeNodeImplementor<?,?,?> node, AttributeNodeImplementor<T,E,K> existingNode) {
if ( existingNode.getAttributeDescriptor() == node.getAttributeDescriptor() ) {
@SuppressWarnings("unchecked") // safe, we just checked
final AttributeNodeImplementor<T> castNode = (AttributeNodeImplementor<T>) node;
final AttributeNodeImplementor<T,E,K> castNode = (AttributeNodeImplementor<T,E,K>) node;
existingNode.merge( castNode );
}
else {
@ -163,19 +194,19 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
@Override
public List<AttributeNodeImplementor<?>> getAttributeNodeList() {
public List<AttributeNodeImplementor<?,?,?>> getAttributeNodeList() {
return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() );
}
@Override
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName) {
public <AJ> AttributeNodeImplementor<AJ,?,?> findAttributeNode(String attributeName) {
final PersistentAttribute<? super J, ?> attribute = findAttributeInSupertypes( attributeName );
@SuppressWarnings("unchecked") // The JPA API is unsafe by nature
final PersistentAttribute<? super J, AJ> persistentAttribute = (PersistentAttribute<? super J, AJ>) attribute;
final AttributeNodeImplementor<AJ> node = attribute == null ? null : findAttributeNode( persistentAttribute );
final AttributeNodeImplementor<AJ,?,?> node = attribute == null ? null : findAttributeNode( persistentAttribute );
if ( node == null && treatedSubgraphs != null ) {
for ( SubGraphImplementor<?> subgraph : treatedSubgraphs.values() ) {
final AttributeNodeImplementor<AJ> subgraphNode = subgraph.findAttributeNode( attributeName );
final AttributeNodeImplementor<AJ,?,?> subgraphNode = subgraph.findAttributeNode( attributeName );
if ( subgraphNode != null ) {
return subgraphNode;
}
@ -188,32 +219,42 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
@Override
public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
public <Y> AttributeNodeImplementor<Y,?,?> getAttributeNode(String attributeName) {
return findAttributeNode( attributeName );
}
@Override
public <AJ> AttributeNodeImplementor<AJ,?,?> findAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
return getNode( attribute );
}
@Override
public <Y> AttributeNodeImplementor<Y,?,?> getAttributeNode(Attribute<? super J, Y> attribute) {
return getNode( (PersistentAttribute<?, ? extends Y>) attribute );
}
@Override
public List<jakarta.persistence.AttributeNode<?>> getAttributeNodes() {
return attributeNodes == null ? emptyList() : new ArrayList<>( attributeNodes.values() );
}
@Override
public Map<PersistentAttribute<? super J, ?>, AttributeNodeImplementor<?>> getNodes() {
public Map<PersistentAttribute<? super J, ?>, AttributeNodeImplementor<?,?,?>> getNodes() {
return attributeNodes == null ? emptyMap() : unmodifiableMap( attributeNodes );
}
@Override
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName) {
public <AJ> AttributeNodeImplementor<AJ,?,?> addAttributeNode(String attributeName) {
return findOrCreateAttributeNode( attributeName );
}
@Override
public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
public <AJ> AttributeNodeImplementor<AJ,?,?> addAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
return findOrCreateAttributeNode( attribute );
}
@Override
public <Y> AttributeNodeImplementor<Y> addAttributeNode(Attribute<? super J, Y> attribute) {
public <Y> AttributeNodeImplementor<Y,?,?> addAttributeNode(Attribute<? super J, Y> attribute) {
return addAttributeNode( (PersistentAttribute<? super J, Y>) attribute );
}
@ -250,11 +291,37 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
@Override
public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
public <AJ> AttributeNodeImplementor<AJ,?,?> findOrCreateAttributeNode(PersistentAttribute<? super J, AJ> attribute) {
verifyMutability();
final AttributeNodeImplementor<AJ> node = getNodeForPut( attribute );
final AttributeNodeImplementor<AJ,?,?> node = getNodeForPut( attribute );
if ( node == null ) {
final AttributeNodeImplementor<AJ> newAttrNode = AttributeNodeImpl.create( attribute, isMutable() );
final AttributeNodeImplementor<AJ,?,?> newAttrNode = AttributeNodeImpl.create( attribute, isMutable() );
attributeNodes.put( attribute, newAttrNode );
return newAttrNode;
}
else {
return node;
}
}
private <C,E> AttributeNodeImplementor<C,E,?> findOrCreateAttributeNode(PluralPersistentAttribute<? super J, C, E> attribute) {
verifyMutability();
final AttributeNodeImplementor<C,E,?> node = getNodeForPut( attribute );
if ( node == null ) {
final AttributeNodeImplementor<C,E,?> newAttrNode = AttributeNodeImpl.create( attribute, isMutable() );
attributeNodes.put( attribute, newAttrNode );
return newAttrNode;
}
else {
return node;
}
}
private <K,V> AttributeNodeImplementor<Map<K,V>,V,K> findOrCreateAttributeNode(MapPersistentAttribute<? super J, K, V> attribute) {
verifyMutability();
final AttributeNodeImplementor<Map<K,V>,V,K> node = getNodeForPut( attribute );
if ( node == null ) {
final AttributeNodeImplementor<Map<K,V>,V,K> newAttrNode = AttributeNodeImpl.create( attribute, isMutable() );
attributeNodes.put( attribute, newAttrNode );
return newAttrNode;
}
@ -264,7 +331,7 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
@Override
public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(String attributeName) {
public <AJ> AttributeNodeImplementor<AJ,?,?> findOrCreateAttributeNode(String attributeName) {
final PersistentAttribute<? super J, ?> attribute = getAttribute( attributeName );
@SuppressWarnings("unchecked") // The JPA API is unsafe by nature
final PersistentAttribute<? super J, AJ> persistentAttribute = (PersistentAttribute<? super J, AJ>) attribute;
@ -285,66 +352,105 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
: attribute;
}
@Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature
public <X> SubGraphImplementor<X> addSubgraph(String attributeName) {
return (SubGraphImplementor<X>) findOrCreateAttributeNode( attributeName ).addValueSubgraph();
}
@Override
public <X> SubGraphImplementor<X> addSubgraph(String attributeName, Class<X> type) {
return addSubgraph( attributeName ).addTreatedSubgraph( type );
}
@Override
public <X> SubGraphImplementor<X> addSubgraph(Attribute<? super J, X> attribute) {
return findOrCreateAttributeNode( (PersistentAttribute<? super J, X>) attribute ).addSingularSubgraph();
}
@Override
@SuppressWarnings("unchecked") // The API is unsafe by nature
public <AJ> SubGraphImplementor<AJ> addSubGraph(String attributeName) {
return (SubGraphImplementor<AJ>) findOrCreateAttributeNode( attributeName ).makeSubGraph();
return addSubgraph( attributeName );
}
@Override
public <AJ> SubGraphImplementor<AJ> addSubGraph(String attributeName, Class<AJ> subtype) {
return findOrCreateAttributeNode( attributeName ).makeSubGraph( subtype );
return addSubGraph( attributeName ).addTreatedSubgraph( subtype );
}
@Override
public <AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, AJ> attribute) {
return findOrCreateAttributeNode( attribute ).makeSubGraph( attribute.getJavaType() );
return addSubgraph( attribute );
}
@Override
public <AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, Class<AJ> subtype) {
return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype );
return addTreatedSubgraph( attribute, subtype );
}
@Override
public <AJ> SubGraphImplementor<AJ> addTreatedSubgraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedType<AJ> subtype) {
return findOrCreateAttributeNode( attribute ).makeSubGraph( subtype );
public <AJ> SubGraphImplementor<AJ> addTreatedSubgraph(Attribute<? super J, ? super AJ> attribute, ManagedType<AJ> type) {
return addSubgraph( attribute ).addTreatedSubgraph( type );
}
@Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName) {
return (SubGraphImplementor<X>) findOrCreateAttributeNode( attributeName ).addElementSubgraph();
}
@Override
public <AJ> SubGraphImplementor<AJ> addElementSubGraph(PluralPersistentAttribute<? super J, ?, ? super AJ> attribute, Class<AJ> type) {
return findOrCreateAttributeNode( attribute ).makeSubGraph( type );
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName, Class<X> type) {
return addElementSubgraph( attributeName ).addTreatedSubgraph( type );
}
@Override
public <AJ> SubGraphImplementor<AJ> addTreatedElementSubgraph(PluralPersistentAttribute<? super J, ?, ? super AJ> attribute, ManagedType<AJ> type) {
return findOrCreateAttributeNode( attribute ).makeSubGraph( type );
public <E> SubGraphImplementor<E> addElementSubgraph(PluralAttribute<? super J, ?, E> attribute) {
return findOrCreateAttributeNode( (PluralPersistentAttribute<? super J, ?, E>) attribute ).addElementSubgraph();
}
@Override
public <AJ> SubGraphImplementor<AJ> addKeySubGraph(MapPersistentAttribute<? super J, ? super AJ, ?> attribute, Class<AJ> subtype) {
return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype );
public <E> SubGraphImplementor<E> addTreatedElementSubgraph(PluralAttribute<? super J, ?, ? super E> attribute, Class<E> type) {
return addElementSubgraph( attribute ).addTreatedSubgraph( type );
}
@Override
public <AJ> SubGraphImplementor<AJ> addTreatedMapKeySubgraph(MapPersistentAttribute<? super J, ? super AJ, ?> attribute, ManagedType<AJ> subtype) {
return findOrCreateAttributeNode( attribute ).makeKeySubGraph( subtype );
public <AJ> SubGraph<AJ> addTreatedElementSubgraph(PluralAttribute<? super J, ?, ? super AJ> attribute, ManagedType<AJ> type) {
return addElementSubgraph( attribute ).addTreatedSubgraph( type );
}
@Override
@SuppressWarnings("unchecked") // The API is unsafe by nature
public <X> SubGraphImplementor<X> addKeySubgraph(String attributeName) {
return (SubGraphImplementor<X>) findOrCreateAttributeNode( attributeName ).addKeySubgraph();
}
@Override
public <X> SubGraphImplementor<X> addKeySubgraph(String attributeName, Class<X> type) {
return addKeySubgraph( attributeName ).addTreatedSubgraph( type );
}
@Override
public <AJ> SubGraphImplementor<AJ> addKeySubGraph(String attributeName) {
return (SubGraphImplementor<AJ>) findOrCreateAttributeNode( attributeName ).makeKeySubGraph();
return addKeySubgraph( attributeName );
}
@Override
public <AJ> SubGraphImplementor<AJ> addKeySubGraph(String attributeName, Class<AJ> subtype) {
return findOrCreateAttributeNode( attributeName ).makeKeySubGraph( subtype );
return addKeySubGraph( attributeName ).addTreatedSubgraph( subtype );
}
@Override
public <K> SubGraphImplementor<K> addMapKeySubgraph(MapAttribute<? super J, K, ?> attribute) {
return findOrCreateAttributeNode( attribute.getName() ).makeKeySubGraph( attribute.getKeyJavaType() );
return findOrCreateAttributeNode( (MapPersistentAttribute<? super J, K, ?>) attribute ).addKeySubgraph();
}
@Override
public <AJ> SubGraphImplementor<AJ> addKeySubGraph(MapPersistentAttribute<? super J, ? super AJ, ?> attribute, Class<AJ> subtype) {
return addTreatedMapKeySubgraph( attribute, subtype );
}
@Override
public <AJ> SubGraphImplementor<AJ> addTreatedMapKeySubgraph(MapAttribute<? super J, ? super AJ, ?> attribute, ManagedType<AJ> type) {
return addMapKeySubgraph( attribute ).addTreatedSubgraph( type );
}
@Override
@ -354,29 +460,6 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
return addMapKeySubgraph( attribute ).addTreatedSubgraph( type );
}
@Override @SuppressWarnings("unchecked") // The JPA API is unsafe by nature
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName) {
return (SubGraphImplementor<X>) findOrCreateAttributeNode( attributeName ).makeSubGraph();
}
@Override
public <E> SubGraphImplementor<E> addElementSubgraph(PluralAttribute<? super J, ?, E> attribute) {
return findOrCreateAttributeNode( attribute.getName() )
.makeSubGraph( asManagedType( attribute.getElementType() ) );
}
@Override
public <X> SubGraphImplementor<X> addElementSubgraph(String attributeName, Class<X> type) {
return findOrCreateAttributeNode( attributeName ).makeSubGraph( type );
}
@Override
public <E> SubGraphImplementor<E> addTreatedElementSubgraph(
PluralAttribute<? super J, ?, ? super E> attribute,
Class<E> type) {
return addElementSubgraph( attribute ).addTreatedSubgraph( type );
}
@Override
public <Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type) {
return addSubgraph( attribute ).addTreatedSubgraph( type );
@ -409,7 +492,7 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
@Override
public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubGraphs() {
public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getTreatedSubgraphs() {
return treatedSubgraphs == null ? emptyMap() : unmodifiableMap( treatedSubgraphs );
}
@ -423,6 +506,16 @@ public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements G
}
}
private <T> ManagedDomainType<T> asManagedType(DomainType<T> domainType) {
if ( domainType instanceof ManagedDomainType<T> managedDomainType ) {
return managedDomainType;
}
else {
throw new CannotContainSubGraphException( "Attribute is of type '" + domainType.getTypeName()
+ "' which is not a managed type" );
}
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder( "Graph[" ).append( managedType.getTypeName() );

View File

@ -16,7 +16,7 @@ import org.hibernate.metamodel.model.domain.EntityDomainType;
*
* @author Steve Ebersole
*/
public class RootGraphImpl<J> extends AbstractGraph<J> implements RootGraphImplementor<J> {
public class RootGraphImpl<J> extends GraphImpl<J> implements RootGraphImplementor<J> {
private final String name;

View File

@ -12,13 +12,13 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType;
*
* @author Steve Ebersole
*/
public class SubGraphImpl<J> extends AbstractGraph<J> implements SubGraphImplementor<J> {
public class SubGraphImpl<J> extends GraphImpl<J> implements SubGraphImplementor<J> {
public SubGraphImpl(ManagedDomainType<J> managedType, boolean mutable) {
super( managedType, mutable );
}
public SubGraphImpl(AbstractGraph<J> original, boolean mutable) {
public SubGraphImpl(GraphImpl<J> original, boolean mutable) {
super( original, mutable );
}

View File

@ -167,7 +167,7 @@ public class GraphParser extends GraphLanguageParserBaseVisitor {
);
}
final AttributeNodeImplementor<?> attributeNode = attributeNodeStack.getCurrent();
final AttributeNodeImplementor<?,?,?> attributeNode = attributeNodeStack.getCurrent();
final SubGraphGenerator subGraphCreator = graphSourceStack.getCurrent();
final SubGraphImplementor<?> subGraph = subGraphCreator.createSubGraph(

View File

@ -15,23 +15,23 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType;
public enum PathQualifierType {
KEY( (attributeNode, subtypeName, sessionFactory) -> subtypeName == null
? attributeNode.makeKeySubGraph()
: attributeNode.makeKeySubGraph( getSubtype( subtypeName, sessionFactory ) )
? attributeNode.addKeySubgraph()
: attributeNode.addKeySubgraph().addTreatedSubgraph( managedType( subtypeName, sessionFactory ) )
),
VALUE( (attributeNode, subtypeName, sessionFactory) -> subtypeName == null
? attributeNode.makeSubGraph()
: attributeNode.makeSubGraph( getSubtype( subtypeName, sessionFactory ) )
? attributeNode.addValueSubgraph()
: attributeNode.addValueSubgraph().addTreatedSubgraph( managedType( subtypeName, sessionFactory ) )
);
private static ManagedDomainType<?> getSubtype(String subtypeName, SessionFactoryImplementor sessionFactory) {
private static <T> ManagedDomainType<T> managedType(String subtypeName, SessionFactoryImplementor sessionFactory) {
final JpaMetamodel metamodel = sessionFactory.getJpaMetamodel();
ManagedDomainType<?> managedType = metamodel.findManagedType( subtypeName );
ManagedDomainType<T> managedType = metamodel.findManagedType( subtypeName );
if ( managedType == null ) {
managedType = metamodel.getHqlEntityReference( subtypeName );
}
if ( managedType == null ) {
throw new IllegalArgumentException( "Unknown type " + subtypeName );
throw new IllegalArgumentException( "Unknown managed type: " + subtypeName );
}
return managedType;
}

View File

@ -14,7 +14,7 @@ import org.hibernate.graph.spi.SubGraphImplementor;
@FunctionalInterface
public interface SubGraphGenerator {
SubGraphImplementor<?> createSubGraph(
AttributeNodeImplementor<?> attributeNode,
AttributeNodeImplementor<?,?,?> attributeNode,
String subTypeName,
SessionFactoryImplementor sessionFactory);
}

View File

@ -4,46 +4,66 @@
*/
package org.hibernate.graph.spi;
import jakarta.persistence.metamodel.ManagedType;
import org.hibernate.graph.AttributeNode;
import java.util.Map;
/**
* Integration version of the {@link AttributeNode} contract
* Integration version of the {@link AttributeNode} contract.
*
* @param <J> The type of the attribute
* @param <E> The element type, if this node represents a
* {@linkplain jakarta.persistence.metamodel.PluralAttribute plural attribute}
* @param <K> The map key type, if this node represents a
* {@linkplain jakarta.persistence.metamodel.MapAttribute map attribute}
*
* @author Strong Liu
* @author Steve Ebersole
* @author Gavin King
*/
public interface AttributeNodeImplementor<J> extends AttributeNode<J>, GraphNodeImplementor<J> {
public interface AttributeNodeImplementor<J, E, K> extends AttributeNode<J>, GraphNodeImplementor<J> {
@Override
AttributeNodeImplementor<J> makeCopy(boolean mutable);
AttributeNodeImplementor<J, E,K> makeCopy(boolean mutable);
@Override
/**
* Create a value subgraph, without knowing whether it represents a singular value or
* plural element, rooted at this attribute node.
*
* @apiNote This version is more lenient and is therefore disfavored. Prefer the use
* of {@link #addSingularSubgraph()} and {@link #addElementSubgraph()}.
*/
SubGraphImplementor<E> addValueSubgraph();
/**
* Create a value subgraph representing a singular value rooted at this attribute node.
*/
SubGraphImplementor<J> addSingularSubgraph();
/**
* Create a value subgraph representing a plural element rooted at this attribute node.
*/
SubGraphImplementor<E> addElementSubgraph();
/**
* Create a key subgraph rooted at this attribute node.
*/
SubGraphImplementor<K> addKeySubgraph();
@Override @Deprecated
SubGraphImplementor<?> makeSubGraph();
@Override
@Override @Deprecated
SubGraphImplementor<?> makeKeySubGraph();
@Override
@Override @Deprecated
<S> SubGraphImplementor<S> makeSubGraph(Class<S> subtype);
@Override
@Override @Deprecated
<S> SubGraphImplementor<S> makeKeySubGraph(Class<S> subtype);
@Override
<S> SubGraphImplementor<S> makeSubGraph(ManagedType<S> subtype);
@Override
<S> SubGraphImplementor<S> makeKeySubGraph(ManagedType<S> subtype);
void merge(AttributeNodeImplementor<J> other);
SubGraphImplementor<?> getSubGraph();
SubGraphImplementor<?> getKeySubGraph();
void merge(AttributeNodeImplementor<J,E,K> other);
@Override
Map<Class<?>, SubGraphImplementor<?>> getSubGraphs();

View File

@ -11,22 +11,20 @@ import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.ManagedType;
import jakarta.persistence.metamodel.MapAttribute;
import jakarta.persistence.metamodel.PluralAttribute;
import org.hibernate.Incubating;
import org.hibernate.Internal;
import org.hibernate.graph.AttributeNode;
import org.hibernate.graph.Graph;
import org.hibernate.graph.SubGraph;
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
/**
* Integration version of the {@link Graph} contract
* Integration version of the {@link Graph} contract.
*
* @author Strong Liu
* @author Steve Ebersole
* @author Andrea Boriero
* @author Gavin King
*/
public interface GraphImplementor<J> extends Graph<J>, GraphNodeImplementor<J> {
@ -47,21 +45,40 @@ public interface GraphImplementor<J> extends Graph<J>, GraphNodeImplementor<J> {
GraphImplementor<J> makeCopy(boolean mutable);
@Override
List<? extends AttributeNodeImplementor<?>> getAttributeNodeList();
List<? extends AttributeNodeImplementor<?,?,?>> getAttributeNodeList();
Map<PersistentAttribute<? super J, ?>, AttributeNodeImplementor<?>> getNodes();
Map<PersistentAttribute<? super J, ?>, AttributeNodeImplementor<?,?,?>> getNodes();
Map<Class<? extends J>, SubGraphImplementor<? extends J>> getTreatedSubgraphs();
@Override
<AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName);
<Y> AttributeNodeImplementor<Y,?,?> getAttributeNode(String attributeName);
@Override
<AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? super J, AJ> attribute);
<Y> AttributeNodeImplementor<Y,?,?> getAttributeNode(Attribute<? super J, Y> attribute);
<AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(String name);
@Override
<AJ> AttributeNodeImplementor<AJ,?,?> findAttributeNode(String attributeName);
<AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAttribute<? super J, AJ> attribute);
@Override
<AJ> AttributeNodeImplementor<AJ,?,?> findAttributeNode(PersistentAttribute<? super J, AJ> attribute);
<AJ> AttributeNodeImplementor<AJ> addAttributeNode(PersistentAttribute<? super J, AJ> attribute);
<AJ> AttributeNodeImplementor<AJ,?,?> findOrCreateAttributeNode(String name);
<AJ> AttributeNodeImplementor<AJ,?,?> findOrCreateAttributeNode(PersistentAttribute<? super J, AJ> attribute);
<AJ> AttributeNodeImplementor<AJ,?,?> addAttributeNode(PersistentAttribute<? super J, AJ> attribute);
@Override
<Y> AttributeNodeImplementor<Y,?,?> addAttributeNode(Attribute<? super J, Y> attribute);
@Override
<Y extends J> SubGraphImplementor<Y> addTreatedSubgraph(Class<Y> type);
<Y extends J> SubGraphImplementor<Y> addTreatedSubgraph(ManagedType<Y> type);
@Override
<X> SubGraphImplementor<X> addSubgraph(String attributeName);
@Override
<AJ> SubGraphImplementor<AJ> addSubGraph(String attributeName);
@ -75,14 +92,6 @@ public interface GraphImplementor<J> extends Graph<J>, GraphNodeImplementor<J> {
@Override
<AJ> SubGraphImplementor<AJ> addSubGraph(PersistentAttribute<? super J, ? super AJ> attribute, Class<AJ> subtype);
<AJ> SubGraphImplementor<AJ> addTreatedSubgraph(PersistentAttribute<? super J, ? super AJ> attribute, ManagedType<AJ> subtype);
@Incubating
<AJ> SubGraphImplementor<AJ> addElementSubGraph(PluralPersistentAttribute<? super J, ?, ? super AJ> attribute, Class<AJ> type);
@Incubating
<AJ> SubGraphImplementor<AJ> addTreatedElementSubgraph(PluralPersistentAttribute<? super J, ?, ? super AJ> attribute, ManagedType<AJ> type);
@Override
<AJ> SubGraphImplementor<AJ> addKeySubGraph(String attributeName);
@ -92,79 +101,35 @@ public interface GraphImplementor<J> extends Graph<J>, GraphNodeImplementor<J> {
@Override
<AJ> SubGraphImplementor<AJ> addKeySubGraph(MapPersistentAttribute<? super J, ? super AJ, ?> attribute, Class<AJ> subtype);
<AJ> SubGraphImplementor<AJ> addTreatedMapKeySubgraph(MapPersistentAttribute<? super J, ? super AJ, ?> attribute, ManagedType<AJ> subtype);
@Override
<X> SubGraphImplementor<X> addSubgraph(String attributeName, Class<X> type);
@Override
<Y extends J> SubGraphImplementor<Y> addTreatedSubgraph(Class<Y> type);
<Y extends J> SubGraphImplementor<Y> addTreatedSubgraph(ManagedType<Y> type);
Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubGraphs();
<X> SubGraphImplementor<X> addSubgraph(Attribute<? super J, X> attribute);
@Override
default <Y> AttributeNode<Y> getAttributeNode(String attributeName) {
return findAttributeNode( attributeName );
}
<Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type);
@Override
default <Y> AttributeNode<Y> getAttributeNode(Attribute<? super J, Y> attribute) {
return findAttributeNode( (PersistentAttribute<? super J, Y>) attribute );
}
<AJ> SubGraphImplementor<AJ> addTreatedSubgraph(Attribute<? super J, ? super AJ> attribute, ManagedType<AJ> type);
@Override
default <Y> AttributeNode<Y> addAttributeNode(Attribute<? super J, Y> attribute) {
return addAttributeNode( (PersistentAttribute<? super J, Y>) attribute );
}
<E> SubGraphImplementor<E> addTreatedElementSubgraph(PluralAttribute<? super J, ?, ? super E> attribute, Class<E> type);
@Override
default <X> SubGraphImplementor<X> addSubgraph(String attributeName, Class<X> type) {
return addSubGraph( attributeName ).addTreatedSubgraph( type );
}
<AJ> SubGraph<AJ> addTreatedElementSubgraph(PluralAttribute<? super J, ?, ? super AJ> attribute, ManagedType<AJ> type);
@Override
default <X> SubGraphImplementor<X> addSubgraph(Attribute<? super J, X> attribute) {
return addSubGraph( (PersistentAttribute<? super J, X>) attribute );
}
<X> SubGraphImplementor<X> addKeySubgraph(String attributeName);
@Override
default <Y> SubGraphImplementor<Y> addTreatedSubgraph(Attribute<? super J, ? super Y> attribute, Class<Y> type) {
return addSubGraph( (PersistentAttribute<? super J, ? super Y>) attribute ).addTreatedSubgraph( type );
}
<X> SubGraphImplementor<X> addKeySubgraph(String attributeName, Class<X> type);
@Override
default <AJ> SubGraph<AJ> addTreatedSubgraph(Attribute<? super J, ? super AJ> attribute, ManagedType<AJ> type) {
return addSubGraph( (PersistentAttribute<? super J, ? super AJ>) attribute ).addTreatedSubgraph( type );
}
<K> SubGraphImplementor<K> addTreatedMapKeySubgraph(MapAttribute<? super J, ? super K, ?> attribute, Class<K> type);
@Override
default <E> SubGraphImplementor<E> addTreatedElementSubgraph(PluralAttribute<? super J, ?, ? super E> attribute, Class<E> type) {
return addElementSubGraph( (PluralPersistentAttribute<? super J, ?, ? super E>) attribute, type );
}
@Override
default <AJ> SubGraph<AJ> addTreatedElementSubgraph(PluralAttribute<? super J, ?, ? super AJ> attribute, ManagedType<AJ> type) {
return addTreatedElementSubgraph( (PluralPersistentAttribute<? super J, ?, ? super AJ>) attribute, type );
}
@Override
default <X> SubGraphImplementor<X> addKeySubgraph(String attributeName) {
return addKeySubGraph( attributeName );
}
@Override
default <X> SubGraphImplementor<X> addKeySubgraph(String attributeName, Class<X> type) {
return addKeySubGraph( attributeName ).addTreatedSubgraph( type );
}
@Override
default <K> SubGraphImplementor<K> addTreatedMapKeySubgraph(MapAttribute<? super J, ? super K, ?> attribute, Class<K> type) {
return addKeySubGraph( (MapPersistentAttribute<? super J, ? super K, ?>) attribute, type );
}
@Override
default <AJ> SubGraph<AJ> addTreatedMapKeySubgraph(MapAttribute<? super J, ? super AJ, ?> attribute, ManagedType<AJ> type) {
return addTreatedMapKeySubgraph( (MapPersistentAttribute<? super J, ? super AJ, ?>) attribute, type );
}
<AJ> SubGraphImplementor<AJ> addTreatedMapKeySubgraph(MapAttribute<? super J, ? super AJ, ?> attribute, ManagedType<AJ> type);
@Override
default boolean hasAttributeNode(String attributeName) {

View File

@ -19,4 +19,7 @@ public interface MapPersistentAttribute<D,K,V> extends MapAttribute<D, K, V>, Pl
@Override
SimpleDomainType<K> getKeyType();
@Override
SimpleDomainType<K> getKeyGraphType();
}

View File

@ -561,8 +561,8 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
GraphImplementor<?> graphNode) {
for ( NamedAttributeNode namedAttributeNode : namedAttributeNodes ) {
final String value = namedAttributeNode.value();
final AttributeNodeImplementor<?> attributeNode =
(AttributeNodeImplementor<?>) graphNode.addAttributeNode( value );
final AttributeNodeImplementor<?,?,?> attributeNode =
(AttributeNodeImplementor<?,?,?>) graphNode.addAttributeNode( value );
if ( isNotEmpty( namedAttributeNode.subgraph() ) ) {
applyNamedSubgraphs(
@ -583,36 +583,52 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
}
}
private <T> void applyNamedSubgraphs(
private <T,E,K> void applyNamedSubgraphs(
NamedEntityGraph namedEntityGraph,
String subgraphName,
AttributeNodeImplementor<T> attributeNode,
AttributeNodeImplementor<T,E,K> attributeNode,
boolean isKeySubGraph) {
for ( NamedSubgraph namedSubgraph : namedEntityGraph.subgraphs() ) {
if ( subgraphName.equals( namedSubgraph.name() ) ) {
final boolean isDefaultSubgraphType = namedSubgraph.type().equals( void.class );
final Class<?> subGraphType = isDefaultSubgraphType ? null : namedSubgraph.type();
final SubGraphImplementor<?> subgraph =
makeAttributeNodeSubgraph( attributeNode, isKeySubGraph, subGraphType );
final Class<?> subgraphType = namedSubgraph.type();
final SubGraphImplementor<?> subgraph;
if ( subgraphType.equals( void.class ) ) { // unspecified
subgraph = attributeNode.addValueSubgraph();
}
else {
subgraph = isKeySubGraph
? makeAttributeNodeKeySubgraph( attributeNode, subgraphType )
: makeAttributeNodeValueSubgraph( attributeNode, subgraphType );
}
applyNamedAttributeNodes( namedSubgraph.attributeNodes(), namedEntityGraph, subgraph );
}
}
}
private static <T> SubGraphImplementor<?> makeAttributeNodeSubgraph(
AttributeNodeImplementor<T> attributeNode,
boolean isKeySubGraph,
Class<?> subGraphType) {
if ( isKeySubGraph ) {
return subGraphType != null
? attributeNode.makeKeySubGraph( subGraphType )
: attributeNode.makeKeySubGraph();
private static <T, E, K> SubGraphImplementor<?> makeAttributeNodeValueSubgraph(
AttributeNodeImplementor<T, E, K> attributeNode, Class<?> subgraphType) {
final Class<?> attributeValueType =
attributeNode.getAttributeDescriptor().getValueGraphType().getBindableJavaType();
if ( !attributeValueType.isAssignableFrom( subgraphType ) ) {
throw new AnnotationException( "Named subgraph type '" + subgraphType.getName()
+ "' is not a subtype of the value type '" + attributeValueType.getName() + "'" );
}
else {
return subGraphType != null
? attributeNode.makeSubGraph( subGraphType )
: attributeNode.makeSubGraph();
@SuppressWarnings("unchecked") // Safe, because we just checked
final Class<? extends E> castType = (Class<? extends E>) subgraphType;
return attributeNode.addValueSubgraph().addTreatedSubgraph( castType );
}
private static <T, E, K> SubGraphImplementor<?> makeAttributeNodeKeySubgraph(
AttributeNodeImplementor<T, E, K> attributeNode, Class<?> subgraphType) {
final Class<?> attributeKeyType =
attributeNode.getAttributeDescriptor().getKeyGraphType().getBindableJavaType();
if ( !attributeKeyType.isAssignableFrom( subgraphType ) ) {
throw new AnnotationException( "Named subgraph type '" + subgraphType.getName()
+ "' is not a subtype of the key type '" + attributeKeyType.getName() + "'" );
}
@SuppressWarnings("unchecked") // Safe, because we just checked
final Class<? extends K> castType = (Class<? extends K>) subgraphType;
return attributeNode.addKeySubgraph().addTreatedSubgraph( castType );
}
private <X> Class<X> resolveRequestedClass(String entityName) {

View File

@ -26,7 +26,7 @@ public class AppliedGraphs {
}
private static boolean containsCollectionFetches(GraphImplementor<?> graph) {
for ( AttributeNodeImplementor<?> node : graph.getNodes().values() ) {
for ( AttributeNodeImplementor<?,?,?> node : graph.getNodes().values() ) {
if ( node.getAttributeDescriptor().isCollection() ) {
return true;
}

View File

@ -260,9 +260,10 @@ public class EntityDelayedFetchInitializer
private boolean isLazyByGraph(RowProcessingState rowProcessingState) {
final AppliedGraph appliedGraph = rowProcessingState.getQueryOptions().getAppliedGraph();
if ( appliedGraph != null && appliedGraph.getSemantic() == GraphSemantic.FETCH ) {
final AttributeNodeImplementor<Object> attributeNode = appliedGraph.getGraph()
.findAttributeNode( navigablePath.getLocalName() );
if ( attributeNode != null && attributeNode.getAttributeDescriptor() == getInitializedPart().asAttributeMapping() ) {
final AttributeNodeImplementor<?,?,?> attributeNode =
appliedGraph.getGraph().findAttributeNode( navigablePath.getLocalName() );
if ( attributeNode != null
&& attributeNode.getAttributeDescriptor() == getInitializedPart().asAttributeMapping() ) {
return false;
}
return true;

View File

@ -55,7 +55,7 @@ public class StandardEntityGraphTraversalStateImpl implements EntityGraphTravers
}
final GraphImplementor<?> previousContextRoot = currentGraphContext;
final AttributeNodeImplementor<?> attributeNode = appliesTo( fetchParent )
final AttributeNodeImplementor<?,?,?> attributeNode = appliesTo( fetchParent )
? currentGraphContext.findAttributeNode( fetchable.getFetchableName() )
: null;

View File

@ -176,11 +176,11 @@ public class EntityGraphParserTest extends AbstractEntityGraphTest {
RootGraphImplementor<GraphParsingTestEntity> graph = parseGraph( "linkToOne(name, description), linkToOne(GraphParsingTestSubEntity: sub)" );
assertNotNull( graph );
List<? extends AttributeNodeImplementor<?>> attrs = graph.getAttributeNodeList();
List<? extends AttributeNodeImplementor<?,?,?>> attrs = graph.getAttributeNodeList();
assertNotNull( attrs );
assertEquals( 1, attrs.size() );
AttributeNodeImplementor<?> linkToOneNode = attrs.get( 0 );
AttributeNodeImplementor<?,?,?> linkToOneNode = attrs.get( 0 );
assertNotNull( linkToOneNode );
assertEquals( "linkToOne", linkToOneNode.getAttributeName() );
@ -204,7 +204,7 @@ public class EntityGraphParserTest extends AbstractEntityGraphTest {
assertEquals( subGraph.getGraphedType().getJavaType(), GraphParsingTestSubEntity.class );
final AttributeNodeImplementor<Object> subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" );
final AttributeNodeImplementor<?,?,?> subTypeAttrNode = subGraph.findOrCreateAttributeNode( "sub" );
assert subTypeAttrNode != null;
}