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() {
|
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) {
|
public EntityManager createEntityManager(Map map) {
|
||||||
|
|
|
@ -24,31 +24,65 @@
|
||||||
package org.hibernate.jpa.internal.graph;
|
package org.hibernate.jpa.internal.graph;
|
||||||
|
|
||||||
import javax.persistence.AttributeNode;
|
import javax.persistence.AttributeNode;
|
||||||
|
import javax.persistence.Subgraph;
|
||||||
import javax.persistence.metamodel.Attribute;
|
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
|
* Hibernate implementation of the JPA AttributeNode contract
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @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;
|
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;
|
this.attribute = attribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public AttributeNodeImpl<T> makeImmutableCopy() {
|
* Intended only for use from {@link #makeImmutableCopy()}
|
||||||
// simple attribute nodes are immutable already
|
*/
|
||||||
return this;
|
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
|
private SessionFactoryImplementor sessionFactory() {
|
||||||
public Type<T> getType() {
|
return (SessionFactoryImplementor) entityManagerFactory.getSessionFactory();
|
||||||
// Linda says this is going away
|
}
|
||||||
return null;
|
|
||||||
|
public Attribute getAttribute() {
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRegistrationName() {
|
||||||
|
return getAttributeName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,12 +90,178 @@ public class AttributeNodeImpl<T> implements AttributeNode<T>, GraphNode<T> {
|
||||||
return attribute.getName();
|
return attribute.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Attribute getAttribute() {
|
@Override
|
||||||
return attribute;
|
public Map<Class, Subgraph> getSubgraphs() {
|
||||||
|
return subgraphMap == null ? Collections.<Class, Subgraph>emptyMap() : subgraphMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRegistrationName() {
|
public Map<Class, Subgraph> getKeySubgraphs() {
|
||||||
return getAttributeName();
|
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.Attribute;
|
||||||
import javax.persistence.metamodel.EntityType;
|
import javax.persistence.metamodel.EntityType;
|
||||||
import javax.persistence.metamodel.IdentifiableType;
|
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 java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.NotYetImplementedException;
|
||||||
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -43,19 +39,14 @@ import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.AttributeDelegate<T> {
|
public class EntityGraphImpl<T> extends GraphNode<T> implements EntityGraph<T> {
|
||||||
private final HibernateEntityManagerFactory entityManagerFactory;
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final EntityType<T> entityType;
|
private final EntityType<T> entityType;
|
||||||
private final GraphDelegate<T> graphDelegate;
|
|
||||||
|
|
||||||
|
|
||||||
public EntityGraphImpl(String name, EntityType<T> entityType, HibernateEntityManagerFactory entityManagerFactory) {
|
public EntityGraphImpl(String name, EntityType<T> entityType, HibernateEntityManagerFactory entityManagerFactory) {
|
||||||
|
super( entityManagerFactory, true );
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.entityType = entityType;
|
this.entityType = entityType;
|
||||||
this.entityManagerFactory = entityManagerFactory;
|
|
||||||
this.graphDelegate = new GraphDelegate<T>( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityGraphImpl<T> makeImmutableCopy(String name) {
|
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) {
|
private EntityGraphImpl(String name, EntityGraphImpl<T> original, boolean mutable) {
|
||||||
|
super( original, mutable );
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.entityType = original.entityType;
|
this.entityType = original.entityType;
|
||||||
this.entityManagerFactory = original.entityManagerFactory;
|
|
||||||
this.graphDelegate = mutable
|
|
||||||
? original.graphDelegate.makeMutableCopy( this )
|
|
||||||
: original.graphDelegate.makeImmutableCopy( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -82,76 +70,67 @@ public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.Attribu
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAttributeNodes(String... attributeNames) {
|
public void addAttributeNodes(String... attributeNames) {
|
||||||
graphDelegate.addAttributeNodes( attributeNames );
|
super.addAttributeNodes( attributeNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAttributeNodes(Attribute<T, ?>... attributes) {
|
public void addAttributeNodes(Attribute<T, ?>... attributes) {
|
||||||
graphDelegate.addAttributeNodes( attributes );
|
super.addAttributeNodes( attributes );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
|
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
|
||||||
return (Subgraph<X>) addSubgraph( attribute, attribute.getJavaType() );
|
return super.addSubgraph( attribute );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
|
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
|
@Override
|
||||||
public <X> Subgraph<X> addSubgraph(String attributeName) {
|
public <X> Subgraph<X> addSubgraph(String attributeName) {
|
||||||
return graphDelegate.addSubgraph( attributeName );
|
return super.addSubgraph( attributeName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
|
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
|
||||||
return graphDelegate.addSubgraph( attributeName, type );
|
return super.addSubgraph( attributeName, type );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
|
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
|
||||||
return (Subgraph<X>) addKeySubgraph( attribute, attribute.getJavaType() );
|
return super.addKeySubgraph( attribute );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
|
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
|
@Override
|
||||||
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
|
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
|
||||||
return graphDelegate.addKeySubgraph( attributeName );
|
return super.addKeySubgraph( attributeName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
|
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
|
||||||
return graphDelegate.addKeySubgraph( attributeName, type );
|
return super.addKeySubgraph( attributeName, type );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T1 extends Object> Subgraph<? extends T1> addSubclassSubgraph(Class<? extends T1> type) {
|
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
|
@Override
|
||||||
public List<AttributeNode<?>> getAttributeNodes() {
|
public List<AttributeNode<?>> getAttributeNodes() {
|
||||||
return new ArrayList<AttributeNode<?>>( graphDelegate.getGraphNodes() );
|
return super.attributeNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// AttributeDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
protected Attribute<T,?> resolveAttribute(String attributeName) {
|
||||||
public AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
|
|
||||||
return buildAttributeNode( resolveAttribute( attributeName ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private Attribute<T,?> resolveAttribute(String attributeName) {
|
|
||||||
final Attribute<T,?> attribute = entityType.getDeclaredAttribute( attributeName );
|
final Attribute<T,?> attribute = entityType.getDeclaredAttribute( attributeName );
|
||||||
if ( attribute == null ) {
|
if ( attribute == null ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -165,90 +144,6 @@ public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.Attribu
|
||||||
return attribute;
|
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) {
|
public boolean appliesTo(EntityType<? super T> entityType) {
|
||||||
if ( this.entityType.equals( entityType ) ) {
|
if ( this.entityType.equals( entityType ) ) {
|
||||||
return true;
|
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;
|
package org.hibernate.jpa.internal.graph;
|
||||||
|
|
||||||
import javax.persistence.AttributeNode;
|
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
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface GraphNode<T> extends AttributeNode<T> {
|
public abstract class GraphNode<T> {
|
||||||
public String getRegistrationName();
|
private static final Logger log = Logger.getLogger( GraphNode.class );
|
||||||
public GraphNode<T> makeImmutableCopy();
|
|
||||||
|
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.Subgraph;
|
||||||
import javax.persistence.metamodel.Attribute;
|
import javax.persistence.metamodel.Attribute;
|
||||||
import javax.persistence.metamodel.ManagedType;
|
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 java.util.List;
|
||||||
|
|
||||||
|
import org.hibernate.jpa.HibernateEntityManagerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SubgraphImpl<T> extends AttributeNodeImpl<T>
|
public class SubgraphImpl<T> extends GraphNode<T> implements Subgraph<T> {
|
||||||
implements Subgraph<T>, GraphNode<T>, GraphDelegate.AttributeDelegate<T> {
|
|
||||||
|
|
||||||
private final ManagedType managedType;
|
private final ManagedType managedType;
|
||||||
private final boolean isMapKeySubgraph;
|
private final Class<T> subclass;
|
||||||
private final GraphDelegate<T> graphDelegate;
|
|
||||||
|
|
||||||
public SubgraphImpl(Attribute attribute, ManagedType managedType) {
|
public SubgraphImpl(
|
||||||
this( attribute, managedType, false );
|
HibernateEntityManagerFactory entityManagerFactory,
|
||||||
}
|
ManagedType managedType,
|
||||||
|
Class<T> subclass) {
|
||||||
public SubgraphImpl(Attribute attribute, ManagedType managedType, boolean isMapKeySubgraph) {
|
super( entityManagerFactory, true );
|
||||||
super( attribute );
|
|
||||||
this.managedType = managedType;
|
this.managedType = managedType;
|
||||||
this.isMapKeySubgraph = isMapKeySubgraph;
|
this.subclass = subclass;
|
||||||
this.graphDelegate = new GraphDelegate<T>( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubgraphImpl(SubgraphImpl<T> original) {
|
private SubgraphImpl(SubgraphImpl<T> original) {
|
||||||
super( original.getAttribute() );
|
super( original, false );
|
||||||
this.managedType = original.managedType;
|
this.managedType = original.managedType;
|
||||||
this.isMapKeySubgraph = original.isMapKeySubgraph;
|
this.subclass = original.subclass;
|
||||||
this.graphDelegate = original.graphDelegate.makeImmutableCopy( this );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubgraphImpl<T> makeImmutableCopy() {
|
public SubgraphImpl<T> makeImmutableCopy() {
|
||||||
return new SubgraphImpl<T>( this );
|
return new SubgraphImpl<T>( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMapKeySubgraph() {
|
|
||||||
return isMapKeySubgraph;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAttributeNodes(String... attributeNames) {
|
public void addAttributeNodes(String... attributeNames) {
|
||||||
graphDelegate.addAttributeNodes( attributeNames );
|
super.addAttributeNodes( attributeNames );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addAttributeNodes(Attribute<T, ?>... attributes) {
|
public void addAttributeNodes(Attribute<T, ?>... attributes) {
|
||||||
graphDelegate.addAttributeNodes( attributes );
|
super.addAttributeNodes( attributes );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
|
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
|
||||||
return (Subgraph<X>) addSubgraph( attribute, attribute.getJavaType() );
|
return super.addSubgraph( attribute );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
|
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
|
@Override
|
||||||
public <X> Subgraph<X> addSubgraph(String attributeName) {
|
public <X> Subgraph<X> addSubgraph(String attributeName) {
|
||||||
return graphDelegate.addSubgraph( attributeName );
|
return super.addSubgraph( attributeName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
|
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
|
||||||
return graphDelegate.addSubgraph( attributeName, type );
|
return super.addSubgraph( attributeName, type );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
|
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
|
||||||
return (Subgraph<X>) addKeySubgraph( attribute, attribute.getJavaType() );
|
return super.addKeySubgraph( attribute );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
|
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
|
@Override
|
||||||
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
|
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
|
||||||
return graphDelegate.addKeySubgraph( attributeName );
|
return super.addKeySubgraph( attributeName );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
|
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
|
||||||
return graphDelegate.addKeySubgraph( attributeName, type );
|
return super.addKeySubgraph( attributeName, type );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -130,20 +115,12 @@ public class SubgraphImpl<T> extends AttributeNodeImpl<T>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AttributeNode<?>> getAttributeNodes() {
|
public List<AttributeNode<?>> getAttributeNodes() {
|
||||||
return new ArrayList<AttributeNode<?>>( graphDelegate.getGraphNodes() );
|
return super.attributeNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// AttributeDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
|
protected Attribute<T,?> resolveAttribute(String attributeName) {
|
||||||
return buildAttributeNode( resolveAttribute( attributeName ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private Attribute<T,?> resolveAttribute(String attributeName) {
|
|
||||||
final Attribute<T,?> attribute = managedType.getDeclaredAttribute( attributeName );
|
final Attribute<T,?> attribute = managedType.getDeclaredAttribute( attributeName );
|
||||||
if ( attribute == null ) {
|
if ( attribute == null ) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
@ -156,89 +133,4 @@ public class SubgraphImpl<T> extends AttributeNodeImpl<T>
|
||||||
}
|
}
|
||||||
return attribute;
|
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',
|
javassist: 'org.javassist:javassist:3.15.0-GA',
|
||||||
|
|
||||||
// javax
|
// 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',
|
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',
|
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',
|
jacc: 'org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec:1.0.2.Final',
|
||||||
|
|
Loading…
Reference in New Issue