HHH-7997 - Integrate changes to EntityGraphs
This commit is contained in:
parent
e5df5541c7
commit
2c5098b9c6
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue