HHH-7997 - Integrate changes to EntityGraphs

This commit is contained in:
Steve Ebersole 2013-03-13 12:08:13 -05:00
parent e5df5541c7
commit 2c5098b9c6
9 changed files with 661 additions and 469 deletions

View File

@ -208,7 +208,12 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
}
public EntityManager createEntityManager() {
return createEntityManager( null );
return createEntityManager( Collections.EMPTY_MAP );
}
@Override
public EntityManager createEntityManager(SynchronizationType synchronizationType) {
return createEntityManager( synchronizationType, Collections.EMPTY_MAP );
}
public EntityManager createEntityManager(Map map) {

View File

@ -24,31 +24,65 @@
package org.hibernate.jpa.internal.graph;
import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.Type;
import javax.persistence.metamodel.PluralAttribute;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.jpa.internal.metamodel.Helper;
import org.hibernate.jpa.internal.metamodel.PluralAttributeImpl;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
/**
* Hibernate implementation of the JPA AttributeNode contract
*
* @author Steve Ebersole
*/
public class AttributeNodeImpl<T> implements AttributeNode<T>, GraphNode<T> {
public class AttributeNodeImpl<T> implements AttributeNode<T> {
private final HibernateEntityManagerFactory entityManagerFactory;
private final Attribute attribute;
public AttributeNodeImpl(Attribute attribute) {
private Map<Class, Subgraph> subgraphMap;
private Map<Class, Subgraph> keySubgraphMap;
public AttributeNodeImpl(HibernateEntityManagerFactory entityManagerFactory, Attribute attribute) {
this.entityManagerFactory = entityManagerFactory;
this.attribute = attribute;
}
@Override
public AttributeNodeImpl<T> makeImmutableCopy() {
// simple attribute nodes are immutable already
return this;
/**
* Intended only for use from {@link #makeImmutableCopy()}
*/
private AttributeNodeImpl(
HibernateEntityManagerFactory entityManagerFactory,
Attribute attribute,
Map<Class, Subgraph> subgraphMap,
Map<Class, Subgraph> keySubgraphMap) {
this.entityManagerFactory = entityManagerFactory;
this.attribute = attribute;
this.subgraphMap = subgraphMap;
this.keySubgraphMap = keySubgraphMap;
}
@Override
public Type<T> getType() {
// Linda says this is going away
return null;
private SessionFactoryImplementor sessionFactory() {
return (SessionFactoryImplementor) entityManagerFactory.getSessionFactory();
}
public Attribute getAttribute() {
return attribute;
}
public String getRegistrationName() {
return getAttributeName();
}
@Override
@ -56,12 +90,178 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, GraphNode<T> {
return attribute.getName();
}
public Attribute getAttribute() {
return attribute;
@Override
public Map<Class, Subgraph> getSubgraphs() {
return subgraphMap == null ? Collections.<Class, Subgraph>emptyMap() : subgraphMap;
}
@Override
public String getRegistrationName() {
return getAttributeName();
public Map<Class, Subgraph> getKeySubgraphs() {
return keySubgraphMap == null ? Collections.<Class, Subgraph>emptyMap() : keySubgraphMap;
}
@SuppressWarnings("unchecked")
public <T> Subgraph<T> makeSubgraph() {
return (Subgraph<T>) makeSubgraph( null );
}
@SuppressWarnings("unchecked")
public <X extends T> Subgraph<X> makeSubgraph(Class<X> type) {
if ( attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.BASIC
|| attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED ) {
throw new IllegalArgumentException(
String.format( "Attribute [%s] is not of managed type", getAttributeName() )
);
}
if ( attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.ELEMENT_COLLECTION ) {
throw new IllegalArgumentException(
String.format( "Collection elements [%s] is not of managed type", getAttributeName() )
);
}
if ( subgraphMap == null ) {
subgraphMap = new HashMap<Class, Subgraph>();
}
final AssociationType attributeType = (AssociationType) Helper.resolveType( sessionFactory(), attribute );
final Joinable joinable = attributeType.getAssociatedJoinable( sessionFactory() );
if ( joinable.isCollection() ) {
final EntityPersister elementEntityPersister = ( (QueryableCollection) joinable ).getElementPersister();
if ( type == null ) {
type = elementEntityPersister.getMappedClass();
}
else {
if ( !isTreatableAs( elementEntityPersister, type ) ) {
throw new IllegalArgumentException(
String.format(
"Collection elements [%s] cannot be treated as requested type [%s] : %s",
getAttributeName(),
type.getName(),
elementEntityPersister.getMappedClass().getName()
)
);
}
}
}
else {
final EntityPersister entityPersister = (EntityPersister) joinable;
if ( type == null ) {
type = entityPersister.getMappedClass();
}
else {
if ( !isTreatableAs( entityPersister, type ) ) {
throw new IllegalArgumentException(
String.format(
"Attribute [%s] cannot be treated as requested type [%s] : %s",
getAttributeName(),
type.getName(),
entityPersister.getMappedClass().getName()
)
);
}
}
}
final SubgraphImpl subgraph = new SubgraphImpl( this.entityManagerFactory, attribute.getDeclaringType(), type );
subgraphMap.put( type, subgraph );
return subgraph;
}
/**
* Check to make sure that the java type of the given entity persister is treatable as the given type. In other
* words, is the given type a subclass of the class represented by the persister.
*
* @param entityPersister The persister to check
* @param type The type to check it against
*
* @return {@code true} indicates it is treatable as such; {@code false} indicates it is not
*/
@SuppressWarnings("unchecked")
private boolean isTreatableAs(EntityPersister entityPersister, Class type) {
return type.isAssignableFrom( entityPersister.getMappedClass() );
}
public <T> Subgraph<T> makeKeySubgraph() {
return (SubgraphImpl<T>) makeKeySubgraph( null );
}
@SuppressWarnings("unchecked")
public <X extends T> Subgraph<X> makeKeySubgraph(Class<X> type) {
if ( ! attribute.isCollection() ) {
throw new IllegalArgumentException(
String.format( "Non-collection attribute [%s] cannot be target of key subgraph", getAttributeName() )
);
}
final PluralAttributeImpl pluralAttribute = (PluralAttributeImpl) attribute;
if ( pluralAttribute.getCollectionType() != PluralAttribute.CollectionType.MAP ) {
throw new IllegalArgumentException(
String.format( "Non-Map attribute [%s] cannot be target of key subgraph", getAttributeName() )
);
}
final AssociationType attributeType = (AssociationType) Helper.resolveType( sessionFactory(), attribute );
final QueryableCollection collectionPersister = (QueryableCollection) attributeType.getAssociatedJoinable( sessionFactory() );
final Type indexType = collectionPersister.getIndexType();
if ( ! indexType.isAssociationType() ) {
throw new IllegalArgumentException(
String.format( "Map index [%s] is not an entity; cannot be target of key subgraph", getAttributeName() )
);
}
if ( keySubgraphMap == null ) {
keySubgraphMap = new HashMap<Class, Subgraph>();
}
final AssociationType indexAssociationType = (AssociationType) indexType;
final EntityPersister indexEntityPersister = (EntityPersister) indexAssociationType.getAssociatedJoinable( sessionFactory() );
if ( type == null ) {
type = indexEntityPersister.getMappedClass();
}
else {
if ( !isTreatableAs( indexEntityPersister, type ) ) {
throw new IllegalArgumentException(
String.format(
"Map key [%s] cannot be treated as requested type [%s] : %s",
getAttributeName(),
type.getName(),
indexEntityPersister.getMappedClass().getName()
)
);
}
}
final SubgraphImpl subgraph = new SubgraphImpl( this.entityManagerFactory, attribute.getDeclaringType(), type );
keySubgraphMap.put( type, subgraph );
return subgraph;
}
AttributeNodeImpl<T> makeImmutableCopy() {
return new AttributeNodeImpl<T>(
this.entityManagerFactory,
this.attribute,
makeSafeMapCopy( subgraphMap ),
makeSafeMapCopy( keySubgraphMap )
);
}
private static Map<Class, Subgraph> makeSafeMapCopy(Map<Class, Subgraph> subgraphMap) {
if ( subgraphMap == null ) {
return null;
}
final int properSize = CollectionHelper.determineProperSizing( subgraphMap );
final HashMap<Class,Subgraph> copy = new HashMap<Class,Subgraph>( properSize );
for ( Map.Entry<Class, Subgraph> subgraphEntry : subgraphMap.entrySet() ) {
copy.put(
subgraphEntry.getKey(),
( ( SubgraphImpl ) subgraphEntry.getValue() ).makeImmutableCopy()
);
}
return copy;
}
}

View File

@ -29,13 +29,9 @@ import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
@ -43,19 +39,14 @@ import org.hibernate.jpa.HibernateEntityManagerFactory;
*
* @author Steve Ebersole
*/
public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.AttributeDelegate<T> {
private final HibernateEntityManagerFactory entityManagerFactory;
public class EntityGraphImpl<T> extends GraphNode<T> implements EntityGraph<T> {
private final String name;
private final EntityType<T> entityType;
private final GraphDelegate<T> graphDelegate;
public EntityGraphImpl(String name, EntityType<T> entityType, HibernateEntityManagerFactory entityManagerFactory) {
super( entityManagerFactory, true );
this.name = name;
this.entityType = entityType;
this.entityManagerFactory = entityManagerFactory;
this.graphDelegate = new GraphDelegate<T>( this );
}
public EntityGraphImpl<T> makeImmutableCopy(String name) {
@ -67,12 +58,9 @@ public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.Attribu
}
private EntityGraphImpl(String name, EntityGraphImpl<T> original, boolean mutable) {
super( original, mutable );
this.name = name;
this.entityType = original.entityType;
this.entityManagerFactory = original.entityManagerFactory;
this.graphDelegate = mutable
? original.graphDelegate.makeMutableCopy( this )
: original.graphDelegate.makeImmutableCopy( this );
}
@Override
@ -82,76 +70,67 @@ public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.Attribu
@Override
public void addAttributeNodes(String... attributeNames) {
graphDelegate.addAttributeNodes( attributeNames );
super.addAttributeNodes( attributeNames );
}
@Override
public void addAttributeNodes(Attribute<T, ?>... attributes) {
graphDelegate.addAttributeNodes( attributes );
super.addAttributeNodes( attributes );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addSubgraph( attribute, attribute.getJavaType() );
return super.addSubgraph( attribute );
}
@Override
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addSubgraph( attribute, type );
return super.addSubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName) {
return graphDelegate.addSubgraph( attributeName );
return super.addSubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
return graphDelegate.addSubgraph( attributeName, type );
return super.addSubgraph( attributeName, type );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addKeySubgraph( attribute, attribute.getJavaType() );
return super.addKeySubgraph( attribute );
}
@Override
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addKeySubgraph( attribute, type );
return super.addKeySubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
return graphDelegate.addKeySubgraph( attributeName );
return super.addKeySubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
return graphDelegate.addKeySubgraph( attributeName, type );
return super.addKeySubgraph( attributeName, type );
}
@Override
public <T1 extends Object> Subgraph<? extends T1> addSubclassSubgraph(Class<? extends T1> type) {
return null; //To change body of implemented methods use File | Settings | File Templates.
// todo : implement
throw new NotYetImplementedException();
}
@Override
public List<AttributeNode<?>> getAttributeNodes() {
return new ArrayList<AttributeNode<?>>( graphDelegate.getGraphNodes() );
return super.attributeNodes();
}
// AttributeDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@SuppressWarnings("unchecked")
public AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
return buildAttributeNode( resolveAttribute( attributeName ) );
}
private Attribute<T,?> resolveAttribute(String attributeName) {
protected Attribute<T,?> resolveAttribute(String attributeName) {
final Attribute<T,?> attribute = entityType.getDeclaredAttribute( attributeName );
if ( attribute == null ) {
throw new IllegalArgumentException(
@ -165,90 +144,6 @@ public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.Attribu
return attribute;
}
@SuppressWarnings("unchecked")
private <X> Attribute<T, ? extends X> resolveAttribute(String attributeName, Class<? extends X> type) {
final Attribute<T,?> attribute = entityType.getDeclaredAttribute( attributeName );
if ( attribute == null ) {
throw new IllegalArgumentException(
String.format(
"Given attribute name [%s] is not an attribute on this entity [%s]",
attributeName,
entityType.getName()
)
);
}
return (Attribute<T, ? extends X>) attribute;
}
@Override
public AttributeNodeImpl<?> buildAttributeNode(Attribute<T, ?> attribute) {
return new AttributeNodeImpl<Object>( attribute );
}
@Override
public SubgraphImpl buildSubgraph(String attributeName) {
final Attribute<T,?> attribute = resolveAttribute( attributeName );
return new SubgraphImpl( attribute, toManagedType( attribute ) );
}
@SuppressWarnings("unchecked")
private <X> ManagedType<X> toManagedType(Attribute<T, X> attribute) {
if ( attribute.isCollection() ) {
final Type elementType = ( (PluralAttribute) attribute ).getElementType();
if ( ! ManagedType.class.isInstance( elementType ) ) {
throw new IllegalArgumentException(
String.format(
"Specified collection attribute [%s] is not comprised of elements of a ManagedType",
attribute.toString()
)
);
}
return (ManagedType<X>) elementType;
}
else {
final Type type = ( (SingularAttribute) attribute ).getType();
if ( ! ManagedType.class.isInstance( type ) ) {
throw new IllegalArgumentException(
String.format( "Specified attribute [%s] is not a ManagedType" , attribute.toString() )
);
}
return (ManagedType<X>) type;
}
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<X> buildSubgraph(String attributeName, Class<X> type) {
final Attribute<T,X> attribute = (Attribute<T, X>) resolveAttribute( attributeName, type );
return new SubgraphImpl<X>( attribute, toManagedType( attribute ) );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<? extends X> buildSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return new SubgraphImpl( attribute, toManagedType( attribute ) );
}
@Override
public SubgraphImpl buildKeySubgraph(String attributeName) {
final Attribute<T,?> attribute = resolveAttribute( attributeName );
return new SubgraphImpl( attribute, toManagedType( attribute ), true );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<X> buildKeySubgraph(String attributeName, Class<X> type) {
final Attribute<T,X> attribute = (Attribute<T, X>) resolveAttribute( attributeName, type );
return new SubgraphImpl<X>( attribute, toManagedType( attribute ), true );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<? extends X> buildKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return new SubgraphImpl( attribute, toManagedType( attribute ), true );
}
public boolean appliesTo(EntityType<? super T> entityType) {
if ( this.entityType.equals( entityType ) ) {
return true;

View File

@ -1,194 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.internal.graph;
import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.internal.util.collections.CollectionHelper;
/**
* @author Steve Ebersole
*/
public class GraphDelegate<T> {
private static final Logger log = Logger.getLogger( GraphDelegate.class );
private final AttributeDelegate<T> attributeDelegate;
private final boolean mutable;
private Map<String, GraphNode<?>> graphNodeMap;
public GraphDelegate(AttributeDelegate<T> attributeDelegate) {
this.attributeDelegate = attributeDelegate;
this.mutable = true;
}
private GraphDelegate(
AttributeDelegate<T> attributeDelegate,
GraphDelegate<T> original,
boolean mutable) {
this.attributeDelegate = attributeDelegate;
this.graphNodeMap = makeSafeGraphNodeMapCopy( original.graphNodeMap );
this.mutable = mutable;
}
public GraphDelegate<T> makeImmutableCopy(AttributeDelegate<T> attributeDelegate) {
return new GraphDelegate<T>( attributeDelegate, this, false );
}
public GraphDelegate<T> makeMutableCopy(AttributeDelegate<T> attributeDelegate) {
return new GraphDelegate<T>( attributeDelegate, this, true );
}
private static Map<String, GraphNode<?>> makeSafeGraphNodeMapCopy(Map<String, GraphNode<?>> graphNodeMap) {
if ( graphNodeMap == null ) {
return null;
}
final HashMap<String,GraphNode<?>> copy
= new HashMap<String,GraphNode<?>>( CollectionHelper.determineProperSizing( graphNodeMap ) );
for ( Map.Entry<String,GraphNode<?>> attributeNodeEntry : graphNodeMap.entrySet() ) {
copy.put(
attributeNodeEntry.getKey(),
attributeNodeEntry.getValue().makeImmutableCopy()
);
}
return copy;
}
public Collection<GraphNode<?>> getGraphNodes() {
return graphNodeMap.values();
}
public void addAttributeNodes(String... attributeNames) {
checkMutability();
for ( String attributeName : attributeNames ) {
addNode( attributeDelegate.buildAttributeNode( attributeName ) );
}
}
private void checkMutability() {
if ( ! mutable ) {
throw new IllegalStateException( "Entity graph is not mutable" );
}
}
private void addNode(GraphNode graphNode) {
if ( graphNodeMap == null ) {
graphNodeMap = new HashMap<String, GraphNode<?>>();
}
else {
final AttributeNode old = graphNodeMap.get( graphNode.getRegistrationName() );
if ( old != null ) {
log.debugf(
"Encountered request to add entity graph node [%s] using a name [%s] under which another " +
"node is already registered [%s]",
old.getClass().getName(),
graphNode.getRegistrationName(),
graphNode.getClass().getName()
);
}
}
graphNodeMap.put( graphNode.getAttributeName(), graphNode );
}
public void addAttributeNodes(Attribute<T, ?>... attributes) {
checkMutability();
for ( Attribute<T,?> attribute : attributes ) {
addNode( attributeDelegate.buildAttributeNode( attribute ) );
}
}
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
checkMutability();
final SubgraphImpl<? extends X> subgraph = attributeDelegate.buildSubgraph( attribute, type );
addNode( subgraph );
return subgraph;
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(String attributeName) {
checkMutability();
final SubgraphImpl<X> subgraph = attributeDelegate.buildSubgraph( attributeName );
addNode( subgraph );
return subgraph;
}
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
checkMutability();
final SubgraphImpl<X> subgraph = attributeDelegate.buildSubgraph( attributeName, type );
addNode( subgraph );
return subgraph;
}
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
checkMutability();
final SubgraphImpl<? extends X> subgraph = attributeDelegate.buildKeySubgraph( attribute, type );
addNode( subgraph );
return subgraph;
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
checkMutability();
final SubgraphImpl<X> subgraph = attributeDelegate.buildKeySubgraph( attributeName );
addNode( subgraph );
return subgraph;
}
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
checkMutability();
final SubgraphImpl<X> subgraph = attributeDelegate.buildKeySubgraph( attributeName, type );
addNode( subgraph );
return subgraph;
}
public static interface AttributeDelegate<T> {
public AttributeNodeImpl<?> buildAttributeNode(String attributeName);
public AttributeNodeImpl<?> buildAttributeNode(Attribute<T,?> attribute);
public SubgraphImpl buildSubgraph(String atributeName);
public <X> SubgraphImpl<X> buildSubgraph(String atributeName, Class<X> type);
public <X> SubgraphImpl<? extends X> buildSubgraph(Attribute<T, X> attribute, Class<? extends X> type);
public SubgraphImpl buildKeySubgraph(String attributeName);
public <X> SubgraphImpl<X> buildKeySubgraph(String attributeName, Class<X> type);
public <X> SubgraphImpl<? extends X> buildKeySubgraph(Attribute<T,X> attribute, Class<? extends X> type);
}
}

View File

@ -24,11 +24,164 @@
package org.hibernate.jpa.internal.graph;
import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
* @author Steve Ebersole
*/
public interface GraphNode<T> extends AttributeNode<T> {
public String getRegistrationName();
public GraphNode<T> makeImmutableCopy();
public abstract class GraphNode<T> {
private static final Logger log = Logger.getLogger( GraphNode.class );
private final HibernateEntityManagerFactory entityManagerFactory;
private final boolean mutable;
private Map<String, AttributeNode<?>> attributeNodeMap;
protected GraphNode(HibernateEntityManagerFactory entityManagerFactory, boolean mutable) {
this.entityManagerFactory = entityManagerFactory;
this.mutable = mutable;
}
protected GraphNode(GraphNode<T> original, boolean mutable) {
this.entityManagerFactory = original.entityManagerFactory;
this.mutable = mutable;
this.attributeNodeMap = makeSafeMapCopy( original.attributeNodeMap );
}
private static Map<String, AttributeNode<?>> makeSafeMapCopy(Map<String, AttributeNode<?>> attributeNodeMap) {
if ( attributeNodeMap == null ) {
return null;
}
final int properSize = CollectionHelper.determineProperSizing( attributeNodeMap );
final HashMap<String,AttributeNode<?>> copy = new HashMap<String,AttributeNode<?>>( properSize );
for ( Map.Entry<String,AttributeNode<?>> attributeNodeEntry : attributeNodeMap.entrySet() ) {
copy.put(
attributeNodeEntry.getKey(),
( ( AttributeNodeImpl ) attributeNodeEntry.getValue() ).makeImmutableCopy()
);
}
return copy;
}
protected HibernateEntityManagerFactory entityManagerFactory() {
return entityManagerFactory;
}
protected List<AttributeNode<?>> attributeNodes() {
if ( attributeNodeMap == null ) {
return Collections.emptyList();
}
else {
return new ArrayList<AttributeNode<?>>( attributeNodeMap.values() );
}
}
protected void addAttributeNodes(String... attributeNames) {
for ( String attributeName : attributeNames ) {
addAttribute( attributeName );
}
}
protected AttributeNodeImpl addAttribute(String attributeName) {
return addAttributeNode( buildAttributeNode( attributeName ) );
}
@SuppressWarnings("unchecked")
private AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
return buildAttributeNode( resolveAttribute( attributeName ) );
}
protected abstract Attribute<T,?> resolveAttribute(String attributeName);
protected AttributeNodeImpl<?> buildAttributeNode(Attribute<T, ?> attribute) {
return new AttributeNodeImpl<Object>( entityManagerFactory, attribute );
}
protected AttributeNodeImpl addAttributeNode(AttributeNodeImpl attributeNode) {
if ( ! mutable ) {
throw new IllegalStateException( "Entity/sub graph is not mutable" );
}
if ( attributeNodeMap == null ) {
attributeNodeMap = new HashMap<String, AttributeNode<?>>();
}
else {
final AttributeNode old = attributeNodeMap.get( attributeNode.getRegistrationName() );
if ( old != null ) {
log.debugf(
"Encountered request to add entity graph node [%s] using a name [%s] under which another " +
"node is already registered [%s]",
old.getClass().getName(),
attributeNode.getRegistrationName(),
attributeNode.getClass().getName()
);
}
}
attributeNodeMap.put( attributeNode.getRegistrationName(), attributeNode );
return attributeNode;
}
protected void addAttributeNodes(Attribute<T, ?>... attributes) {
for ( Attribute attribute : attributes ) {
addAttribute( attribute );
}
}
@SuppressWarnings("unchecked")
protected AttributeNodeImpl addAttribute(Attribute attribute) {
return addAttributeNode( buildAttributeNode( attribute ) );
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
return addAttribute( attribute ).makeSubgraph();
}
@SuppressWarnings("unchecked")
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return addAttribute( attribute ).makeSubgraph( type );
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(String attributeName) {
return addAttribute( attributeName ).makeSubgraph();
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
return addAttribute( attributeName ).makeSubgraph( type );
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
return addAttribute( attribute ).makeKeySubgraph();
}
@SuppressWarnings("unchecked")
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return addAttribute( attribute ).makeKeySubgraph( type );
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
return addAttribute( attributeName ).makeKeySubgraph();
}
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
return addAttribute( attributeName ).makeKeySubgraph( type );
}
}

View File

@ -27,99 +27,84 @@ import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.Type;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.jpa.HibernateEntityManagerFactory;
/**
* @author Steve Ebersole
*/
public class SubgraphImpl<T> extends AttributeNodeImpl<T>
implements Subgraph<T>, GraphNode<T>, GraphDelegate.AttributeDelegate<T> {
public class SubgraphImpl<T> extends GraphNode<T> implements Subgraph<T> {
private final ManagedType managedType;
private final boolean isMapKeySubgraph;
private final GraphDelegate<T> graphDelegate;
private final Class<T> subclass;
public SubgraphImpl(Attribute attribute, ManagedType managedType) {
this( attribute, managedType, false );
}
public SubgraphImpl(Attribute attribute, ManagedType managedType, boolean isMapKeySubgraph) {
super( attribute );
public SubgraphImpl(
HibernateEntityManagerFactory entityManagerFactory,
ManagedType managedType,
Class<T> subclass) {
super( entityManagerFactory, true );
this.managedType = managedType;
this.isMapKeySubgraph = isMapKeySubgraph;
this.graphDelegate = new GraphDelegate<T>( this );
this.subclass = subclass;
}
private SubgraphImpl(SubgraphImpl<T> original) {
super( original.getAttribute() );
super( original, false );
this.managedType = original.managedType;
this.isMapKeySubgraph = original.isMapKeySubgraph;
this.graphDelegate = original.graphDelegate.makeImmutableCopy( this );
this.subclass = original.subclass;
}
@Override
public SubgraphImpl<T> makeImmutableCopy() {
return new SubgraphImpl<T>( this );
}
public boolean isMapKeySubgraph() {
return isMapKeySubgraph;
}
@Override
public void addAttributeNodes(String... attributeNames) {
graphDelegate.addAttributeNodes( attributeNames );
super.addAttributeNodes( attributeNames );
}
@Override
public void addAttributeNodes(Attribute<T, ?>... attributes) {
graphDelegate.addAttributeNodes( attributes );
super.addAttributeNodes( attributes );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addSubgraph( attribute, attribute.getJavaType() );
return super.addSubgraph( attribute );
}
@Override
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addSubgraph( attribute, type );
return super.addSubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName) {
return graphDelegate.addSubgraph( attributeName );
return super.addSubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
return graphDelegate.addSubgraph( attributeName, type );
return super.addSubgraph( attributeName, type );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addKeySubgraph( attribute, attribute.getJavaType() );
return super.addKeySubgraph( attribute );
}
@Override
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addKeySubgraph( attribute, type );
return super.addKeySubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
return graphDelegate.addKeySubgraph( attributeName );
return super.addKeySubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
return graphDelegate.addKeySubgraph( attributeName, type );
return super.addKeySubgraph( attributeName, type );
}
@Override
@ -130,20 +115,12 @@ public class SubgraphImpl<T> extends AttributeNodeImpl<T>
@Override
public List<AttributeNode<?>> getAttributeNodes() {
return new ArrayList<AttributeNode<?>>( graphDelegate.getGraphNodes() );
return super.attributeNodes();
}
// AttributeDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@SuppressWarnings("unchecked")
public AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
return buildAttributeNode( resolveAttribute( attributeName ) );
}
@SuppressWarnings("unchecked")
private Attribute<T,?> resolveAttribute(String attributeName) {
protected Attribute<T,?> resolveAttribute(String attributeName) {
final Attribute<T,?> attribute = managedType.getDeclaredAttribute( attributeName );
if ( attribute == null ) {
throw new IllegalArgumentException(
@ -156,89 +133,4 @@ public class SubgraphImpl<T> extends AttributeNodeImpl<T>
}
return attribute;
}
@SuppressWarnings("unchecked")
private <X> Attribute<T, ? extends X> resolveAttribute(String attributeName, Class<? extends X> type) {
final Attribute<T,?> attribute = managedType.getDeclaredAttribute( attributeName );
if ( attribute == null ) {
throw new IllegalArgumentException(
String.format(
"Given attribute name [%s] is not an attribute on this class [%s]",
attributeName,
managedType.getClass().getName()
)
);
}
return (Attribute<T, ? extends X>) attribute;
}
@Override
public AttributeNodeImpl<?> buildAttributeNode(Attribute<T, ?> attribute) {
return new AttributeNodeImpl<Object>( attribute );
}
@Override
public SubgraphImpl buildSubgraph(String attributeName) {
final Attribute<T,?> attribute = resolveAttribute( attributeName );
return new SubgraphImpl( attribute, toManagedType( attribute ) );
}
@SuppressWarnings("unchecked")
private <X> ManagedType<X> toManagedType(Attribute<T, X> attribute) {
if ( attribute.isCollection() ) {
final Type elementType = ( (PluralAttribute) attribute ).getElementType();
if ( ! ManagedType.class.isInstance( elementType ) ) {
throw new IllegalArgumentException(
String.format(
"Specified collection attribute [%s] is not comprised of elements of a ManagedType",
attribute.toString()
)
);
}
return (ManagedType<X>) elementType;
}
else {
final Type type = ( (SingularAttribute) attribute ).getType();
if ( ! ManagedType.class.isInstance( type ) ) {
throw new IllegalArgumentException(
String.format( "Specified attribute [%s] is not a ManagedType" , attribute.toString() )
);
}
return (ManagedType<X>) type;
}
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<X> buildSubgraph(String attributeName, Class<X> type) {
final Attribute<T,X> attribute = (Attribute<T, X>) resolveAttribute( attributeName, type );
return new SubgraphImpl<X>( attribute, toManagedType( attribute ) );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<? extends X> buildSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return new SubgraphImpl( attribute, toManagedType( attribute ) );
}
@Override
public SubgraphImpl buildKeySubgraph(String attributeName) {
final Attribute<T,?> attribute = resolveAttribute( attributeName );
return new SubgraphImpl( attribute, toManagedType( attribute ), true );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<X> buildKeySubgraph(String attributeName, Class<X> type) {
final Attribute<T,X> attribute = (Attribute<T, X>) resolveAttribute( attributeName, type );
return new SubgraphImpl<X>( attribute, toManagedType( attribute ), true );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<? extends X> buildKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return new SubgraphImpl( attribute, toManagedType( attribute ), true );
}
}

View File

@ -0,0 +1,115 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.internal.metamodel;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.ManagedType;
import org.jboss.logging.Logger;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
/**
* @author Steve Ebersole
*/
public class Helper {
private static final Logger log = Logger.getLogger( Helper.class );
private final SessionFactoryImplementor sessionFactory;
public Helper(SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
}
public static interface AttributeSource {
public Type findType(String attributeName);
}
public AttributeSource resolveAttributeSource(ManagedType managedType) {
return resolveAttributeSource( sessionFactory, managedType );
}
public static AttributeSource resolveAttributeSource(SessionFactoryImplementor sessionFactory, ManagedType managedType) {
if ( EmbeddableTypeImpl.class.isInstance( managedType ) ) {
return new ComponentAttributeSource( ( (EmbeddableTypeImpl) managedType ).getHibernateType() );
}
else if ( IdentifiableType.class.isInstance( managedType ) ) {
final String entityName = managedType.getJavaType().getName();
log.debugf( "Attempting to resolve managed type as entity using %s", entityName );
return new EntityPersisterAttributeSource( sessionFactory.getEntityPersister( entityName ) );
}
else {
throw new IllegalArgumentException(
String.format( "Unknown ManagedType implementation [%s]", managedType.getClass() )
);
}
}
public static class EntityPersisterAttributeSource implements AttributeSource {
private final EntityPersister entityPersister;
public EntityPersisterAttributeSource(EntityPersister entityPersister) {
this.entityPersister = entityPersister;
}
@Override
public Type findType(String attributeName) {
return entityPersister.getPropertyType( attributeName );
}
}
public static class ComponentAttributeSource implements AttributeSource {
private final CompositeType compositeType;
public ComponentAttributeSource(CompositeType compositeType) {
this.compositeType = compositeType;
}
@Override
public Type findType(String attributeName) {
int i = 0;
for ( String componentAttributeName : compositeType.getPropertyNames() ) {
if ( attributeName.equals( componentAttributeName ) ) {
return compositeType.getSubtypes()[i];
}
i++;
}
throw new IllegalArgumentException( "Could not find given attribute name [%s] on composite-type" );
}
}
public Type resolveType(Attribute attribute) {
return resolveType( sessionFactory, attribute );
}
public static Type resolveType(SessionFactoryImplementor sessionFactory, Attribute attribute) {
return resolveAttributeSource( sessionFactory, attribute.getDeclaringType() ).findType( attribute.getName() );
}
}

View File

@ -0,0 +1,126 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.jpa.test.graphs;
import javax.persistence.AttributeNode;
import javax.persistence.Entity;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Subgraph;
import java.util.Set;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* @author Steve Ebersole
*/
public class BasicEntityGraphTests extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[] { Entity1.class };
}
@Test
public void testBasicGraphBuilding() {
EntityManager em = getOrCreateEntityManager();
EntityGraph<Entity1> graphRoot = em.createEntityGraph( Entity1.class );
assertNull( graphRoot.getName() );
assertEquals( 0, graphRoot.getAttributeNodes().size() );
}
@Test
public void testBasicSubgraphBuilding() {
EntityManager em = getOrCreateEntityManager();
EntityGraph<Entity1> graphRoot = em.createEntityGraph( Entity1.class );
Subgraph<Entity1> parentGraph = graphRoot.addSubgraph( "parent" );
Subgraph<Entity1> childGraph = graphRoot.addSubgraph( "children" );
assertNull( graphRoot.getName() );
assertEquals( 2, graphRoot.getAttributeNodes().size() );
assertTrue(
graphRoot.getAttributeNodes().get( 0 ).getSubgraphs().containsValue( parentGraph )
|| graphRoot.getAttributeNodes().get( 0 ).getSubgraphs().containsValue( childGraph )
);
assertTrue(
graphRoot.getAttributeNodes().get( 1 ).getSubgraphs().containsValue( parentGraph )
|| graphRoot.getAttributeNodes().get( 1 ).getSubgraphs().containsValue( childGraph )
);
}
@Test
public void testBasicGraphImmutability() {
EntityManager em = getOrCreateEntityManager();
EntityGraph<Entity1> graphRoot = em.createEntityGraph( Entity1.class );
graphRoot.addSubgraph( "parent" );
graphRoot.addSubgraph( "children" );
em.getEntityManagerFactory().addNamedEntityGraph( "immutable", graphRoot );
graphRoot = em.getEntityGraph( "immutable" );
assertEquals( "immutable", graphRoot.getName() );
assertEquals( 2, graphRoot.getAttributeNodes().size() );
try {
graphRoot.addAttributeNodes( "parent" );
fail( "Should have failed" );
}
catch (IllegalStateException ignore) {
// expected outcome
}
for ( AttributeNode attrNode : graphRoot.getAttributeNodes() ) {
assertEquals( 1, attrNode.getSubgraphs().size() );
Subgraph subgraph = (Subgraph) attrNode.getSubgraphs().values().iterator().next();
try {
graphRoot.addAttributeNodes( "parent" );
fail( "Should have failed" );
}
catch (IllegalStateException ignore) {
// expected outcome
}
}
}
@Entity( name = "Entity1" )
public static class Entity1 {
@Id
public Integer id;
public String name;
@ManyToOne
public Entity1 parent;
@OneToMany( mappedBy = "parent" )
public Set<Entity1> children;
}
}

View File

@ -54,7 +54,7 @@ ext {
javassist: 'org.javassist:javassist:3.15.0-GA',
// javax
jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Draft-10',
jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Draft-14',
jta: 'org.jboss.spec.javax.transaction:jboss-transaction-api_1.1_spec:1.0.0.Final',
validation: 'javax.validation:validation-api:1.0.0.GA',
jacc: 'org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec:1.0.2.Final',