HHH-7957 - Integrate Public Review Draft of the JPA 2.1 spec : entity graph support - phase 1

This commit is contained in:
Steve Ebersole 2013-01-31 09:17:19 -06:00
parent 76c14b1697
commit 5c453fee8d
10 changed files with 910 additions and 9 deletions

View File

@ -22,8 +22,10 @@
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*/ */
package org.hibernate.cfg.annotations; package org.hibernate.cfg.annotations;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ForeignKey;
import javax.persistence.JoinColumn; import javax.persistence.JoinColumn;
import javax.persistence.MapKeyJoinColumn; import javax.persistence.MapKeyJoinColumn;
@ -38,38 +40,52 @@ public class MapKeyJoinColumnDelegator implements JoinColumn {
this.column = column; this.column = column;
} }
@Override
public String name() { public String name() {
return column.name(); return column.name();
} }
@Override
public String referencedColumnName() { public String referencedColumnName() {
return column.referencedColumnName(); return column.referencedColumnName();
} }
@Override
public boolean unique() { public boolean unique() {
return column.unique(); return column.unique();
} }
@Override
public boolean nullable() { public boolean nullable() {
return column.nullable(); return column.nullable();
} }
@Override
public boolean insertable() { public boolean insertable() {
return column.insertable(); return column.insertable();
} }
@Override
public boolean updatable() { public boolean updatable() {
return column.updatable(); return column.updatable();
} }
@Override
public String columnDefinition() { public String columnDefinition() {
return column.columnDefinition(); return column.columnDefinition();
} }
@Override
public String table() { public String table() {
return column.table(); return column.table();
} }
@Override
public ForeignKey foreignKey() {
return column.foreignKey();
}
@Override
public Class<? extends Annotation> annotationType() { public Class<? extends Annotation> annotationType() {
return Column.class; return Column.class;
} }

View File

@ -33,14 +33,11 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jboss.logging.Logger;
import org.hibernate.jpa.internal.EntityManagerMessageLogger;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor; import org.hibernate.jpa.boot.internal.ParsedPersistenceXmlDescriptor;
import org.hibernate.jpa.boot.internal.PersistenceXmlParser; import org.hibernate.jpa.boot.internal.PersistenceXmlParser;
import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.Bootstrap;
import org.hibernate.jpa.boot.spi.ProviderChecker; import org.hibernate.jpa.boot.spi.ProviderChecker;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
/** /**
* The Hibernate {@link PersistenceProvider} implementation * The Hibernate {@link PersistenceProvider} implementation
@ -49,10 +46,6 @@ import org.hibernate.jpa.boot.spi.ProviderChecker;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class HibernatePersistenceProvider implements PersistenceProvider { public class HibernatePersistenceProvider implements PersistenceProvider {
private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(
EntityManagerMessageLogger.class,
HibernatePersistenceProvider.class.getName()
);
private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache(); private final PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
@ -103,6 +96,17 @@ public class HibernatePersistenceProvider implements PersistenceProvider {
return Bootstrap.getEntityManagerFactoryBuilder( info, integration ).build(); return Bootstrap.getEntityManagerFactoryBuilder( info, integration ).build();
} }
@Override
public void generateSchema(PersistenceUnitInfo info, Map map) {
// todo : implement
}
@Override
public boolean generateSchema(String persistenceUnitName, Map map) {
// todo : implement
return false;
}
private final ProviderUtil providerUtil = new ProviderUtil() { private final ProviderUtil providerUtil = new ProviderUtil() {
@Override @Override
public LoadState isLoadedWithoutReference(Object proxy, String property) { public LoadState isLoadedWithoutReference(Object proxy, String property) {

View File

@ -24,6 +24,7 @@
package org.hibernate.jpa.internal; package org.hibernate.jpa.internal;
import javax.persistence.Cache; import javax.persistence.Cache;
import javax.persistence.EntityGraph;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory; import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContextType; import javax.persistence.PersistenceContextType;
@ -32,6 +33,8 @@ import javax.persistence.PersistenceUnitUtil;
import javax.persistence.Query; import javax.persistence.Query;
import javax.persistence.SynchronizationType; import javax.persistence.SynchronizationType;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.Metamodel; import javax.persistence.metamodel.Metamodel;
import javax.persistence.spi.LoadState; import javax.persistence.spi.LoadState;
import javax.persistence.spi.PersistenceUnitTransactionType; import javax.persistence.spi.PersistenceUnitTransactionType;
@ -39,10 +42,13 @@ import java.io.IOException;
import java.io.InvalidObjectException; import java.io.InvalidObjectException;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -64,6 +70,7 @@ import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.HibernateQuery; import org.hibernate.jpa.HibernateQuery;
import org.hibernate.jpa.boot.internal.SettingsImpl; import org.hibernate.jpa.boot.internal.SettingsImpl;
import org.hibernate.jpa.criteria.CriteriaBuilderImpl; import org.hibernate.jpa.criteria.CriteriaBuilderImpl;
import org.hibernate.jpa.internal.graph.EntityGraphImpl;
import org.hibernate.jpa.internal.metamodel.MetamodelImpl; import org.hibernate.jpa.internal.metamodel.MetamodelImpl;
import org.hibernate.jpa.internal.util.PersistenceUtilHelper; import org.hibernate.jpa.internal.util.PersistenceUtilHelper;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
@ -94,6 +101,7 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
private final String entityManagerFactoryName; private final String entityManagerFactoryName;
private final transient PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache(); private final transient PersistenceUtilHelper.MetadataCache cache = new PersistenceUtilHelper.MetadataCache();
private final transient Map<String,EntityGraphImpl> entityGraphs = new ConcurrentHashMap<String, EntityGraphImpl>();
@SuppressWarnings( "unchecked" ) @SuppressWarnings( "unchecked" )
public EntityManagerFactoryImpl( public EntityManagerFactoryImpl(
@ -321,6 +329,40 @@ public class EntityManagerFactoryImpl implements HibernateEntityManagerFactory {
throw new PersistenceException( "Hibernate cannot unwrap EntityManagerFactory as " + cls.getName() ); throw new PersistenceException( "Hibernate cannot unwrap EntityManagerFactory as " + cls.getName() );
} }
@Override
public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph) {
if ( ! EntityGraphImpl.class.isInstance( entityGraph ) ) {
throw new IllegalArgumentException(
"Unknown type of EntityGraph for making named : " + entityGraph.getClass().getName()
);
}
final EntityGraphImpl<T> copy = ( (EntityGraphImpl<T>) entityGraph ).makeImmutableCopy( graphName );
final EntityGraphImpl old = entityGraphs.put( graphName, copy );
if ( old != null ) {
log.debugf( "EntityGraph being replaced on EntityManagerFactory for name %s", graphName );
}
}
public EntityGraphImpl findEntityGraphByName(String name) {
return entityGraphs.get( name );
}
@SuppressWarnings("unchecked")
public <T> List<EntityGraph<? super T>> findEntityGraphsByType(Class<T> entityClass) {
final EntityType<T> entityType = getMetamodel().entity( entityClass );
if ( entityType == null ) {
throw new IllegalArgumentException( "Given class is not an entity : " + entityClass.getName() );
}
final List<EntityGraph<? super T>> results = new ArrayList<EntityGraph<? super T>>();
for ( EntityGraphImpl entityGraph : this.entityGraphs.values() ) {
if ( entityGraph.appliesTo( entityType ) ) {
results.add( entityGraph );
}
}
return results;
}
public boolean isOpen() { public boolean isOpen() {
return ! sessionFactory.isClosed(); return ! sessionFactory.isClosed();
} }

View File

@ -23,10 +23,13 @@
*/ */
package org.hibernate.jpa.internal; package org.hibernate.jpa.internal;
import javax.persistence.EntityGraph;
import javax.persistence.PersistenceContextType; import javax.persistence.PersistenceContextType;
import javax.persistence.PersistenceException; import javax.persistence.PersistenceException;
import javax.persistence.SynchronizationType; import javax.persistence.SynchronizationType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.spi.PersistenceUnitTransactionType; import javax.persistence.spi.PersistenceUnitTransactionType;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -40,6 +43,7 @@ import org.hibernate.engine.spi.SessionBuilderImplementor;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SessionOwner; import org.hibernate.engine.spi.SessionOwner;
import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.AvailableSettings;
import org.hibernate.jpa.internal.graph.EntityGraphImpl;
/** /**
* Hibernate implementation of {@link javax.persistence.EntityManager}. * Hibernate implementation of {@link javax.persistence.EntityManager}.
@ -159,6 +163,35 @@ public class EntityManagerImpl extends AbstractEntityManagerImpl implements Sess
} }
} }
@Override
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
return new EntityGraphImpl<T>( null, getMetamodel().entity( rootType ), getEntityManagerFactory() );
}
@Override
public EntityGraph<?> createEntityGraph(String graphName) {
final EntityGraphImpl named = getEntityManagerFactory().findEntityGraphByName( graphName );
if ( named == null ) {
return null;
}
return named.makeMutableCopy();
}
@Override
@SuppressWarnings("unchecked")
public <T> EntityGraph<T> getEntityGraph(String graphName) {
final EntityGraphImpl named = getEntityManagerFactory().findEntityGraphByName( graphName );
if ( named == null ) {
throw new IllegalArgumentException( "Could not locate EntityGraph with given name : " + graphName );
}
return named;
}
@Override
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
return getEntityManagerFactory().findEntityGraphsByType( entityClass );
}
@Override @Override
public boolean shouldAutoCloseSession() { public boolean shouldAutoCloseSession() {
return !isOpen(); return !isOpen();

View File

@ -0,0 +1,67 @@
/*
* 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.metamodel.Attribute;
import javax.persistence.metamodel.Type;
/**
* Hibernate implementation of the JPA AttributeNode contract
*
* @author Steve Ebersole
*/
public class AttributeNodeImpl<T> implements AttributeNode<T>, GraphNode<T> {
private final Attribute attribute;
public AttributeNodeImpl(Attribute attribute) {
this.attribute = attribute;
}
@Override
public AttributeNodeImpl<T> makeImmutableCopy() {
// simple attribute nodes are immutable already
return this;
}
@Override
public Type<T> getType() {
// Linda says this is going away
return null;
}
@Override
public String getAttributeName() {
return attribute.getName();
}
public Attribute getAttribute() {
return attribute;
}
@Override
public String getRegistrationName() {
return getAttributeName();
}
}

View File

@ -0,0 +1,267 @@
/*
* 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.EntityGraph;
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.jpa.HibernateEntityManagerFactory;
/**
* The Hibernate implementation of the JPA EntityGraph contract.
*
* @author Steve Ebersole
*/
public class EntityGraphImpl<T> implements EntityGraph<T>, GraphDelegate.AttributeDelegate<T> {
private final HibernateEntityManagerFactory entityManagerFactory;
private final String name;
private final EntityType<T> entityType;
private final GraphDelegate<T> graphDelegate;
public EntityGraphImpl(String name, EntityType<T> entityType, HibernateEntityManagerFactory entityManagerFactory) {
this.name = name;
this.entityType = entityType;
this.entityManagerFactory = entityManagerFactory;
this.graphDelegate = new GraphDelegate<T>( this );
}
public EntityGraphImpl<T> makeImmutableCopy(String name) {
return new EntityGraphImpl<T>( name, this, false );
}
public EntityGraphImpl<T> makeMutableCopy() {
return new EntityGraphImpl<T>( name, this, true );
}
private EntityGraphImpl(String name, EntityGraphImpl<T> original, boolean mutable) {
this.name = name;
this.entityType = original.entityType;
this.entityManagerFactory = original.entityManagerFactory;
this.graphDelegate = mutable
? original.graphDelegate.makeMutableCopy( this )
: original.graphDelegate.makeImmutableCopy( this );
}
@Override
public String getName() {
return name;
}
@Override
public void addAttributeNodes(String... attributeNames) {
graphDelegate.addAttributeNodes( attributeNames );
}
@Override
public void addAttributeNodes(Attribute<T, ?>... attributes) {
graphDelegate.addAttributeNodes( attributes );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addSubgraph( attribute, attribute.getJavaType() );
}
@Override
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addSubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName) {
return graphDelegate.addSubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
return graphDelegate.addSubgraph( attributeName, type );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addKeySubgraph( attribute, attribute.getJavaType() );
}
@Override
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addKeySubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
return graphDelegate.addKeySubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
return graphDelegate.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.
}
@Override
public List<AttributeNode<?>> getAttributeNodes() {
return new ArrayList<AttributeNode<?>>( graphDelegate.getGraphNodes() );
}
// AttributeDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@SuppressWarnings("unchecked")
public AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
return buildAttributeNode( resolveAttribute( attributeName ) );
}
private Attribute<T,?> resolveAttribute(String attributeName) {
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;
}
@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;
}
IdentifiableType superType = entityType.getSupertype();
while ( superType != null ) {
if ( superType.equals( entityType ) ) {
return true;
}
superType = superType.getSupertype();
}
return false;
}
}

View File

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

View File

@ -0,0 +1,34 @@
/*
* 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;
/**
* @author Steve Ebersole
*/
public interface GraphNode<T> extends AttributeNode<T> {
public String getRegistrationName();
public GraphNode<T> makeImmutableCopy();
}

View File

@ -0,0 +1,244 @@
/*
* 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 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;
/**
* @author Steve Ebersole
*/
public class SubgraphImpl<T> extends AttributeNodeImpl<T>
implements Subgraph<T>, GraphNode<T>, GraphDelegate.AttributeDelegate<T> {
private final ManagedType managedType;
private final boolean isMapKeySubgraph;
private final GraphDelegate<T> graphDelegate;
public SubgraphImpl(Attribute attribute, ManagedType managedType) {
this( attribute, managedType, false );
}
public SubgraphImpl(Attribute attribute, ManagedType managedType, boolean isMapKeySubgraph) {
super( attribute );
this.managedType = managedType;
this.isMapKeySubgraph = isMapKeySubgraph;
this.graphDelegate = new GraphDelegate<T>( this );
}
private SubgraphImpl(SubgraphImpl<T> original) {
super( original.getAttribute() );
this.managedType = original.managedType;
this.isMapKeySubgraph = original.isMapKeySubgraph;
this.graphDelegate = original.graphDelegate.makeImmutableCopy( this );
}
@Override
public SubgraphImpl<T> makeImmutableCopy() {
return new SubgraphImpl<T>( this );
}
public boolean isMapKeySubgraph() {
return isMapKeySubgraph;
}
@Override
public void addAttributeNodes(String... attributeNames) {
graphDelegate.addAttributeNodes( attributeNames );
}
@Override
public void addAttributeNodes(Attribute<T, ?>... attributes) {
graphDelegate.addAttributeNodes( attributes );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addSubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addSubgraph( attribute, attribute.getJavaType() );
}
@Override
public <X> Subgraph<? extends X> addSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addSubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName) {
return graphDelegate.addSubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addSubgraph(String attributeName, Class<X> type) {
return graphDelegate.addSubgraph( attributeName, type );
}
@Override
@SuppressWarnings("unchecked")
public <X> Subgraph<X> addKeySubgraph(Attribute<T, X> attribute) {
return (Subgraph<X>) addKeySubgraph( attribute, attribute.getJavaType() );
}
@Override
public <X> Subgraph<? extends X> addKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return graphDelegate.addKeySubgraph( attribute, type );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName) {
return graphDelegate.addKeySubgraph( attributeName );
}
@Override
public <X> Subgraph<X> addKeySubgraph(String attributeName, Class<X> type) {
return graphDelegate.addKeySubgraph( attributeName, type );
}
@Override
@SuppressWarnings("unchecked")
public Class<T> getClassType() {
return managedType.getJavaType();
}
@Override
public List<AttributeNode<?>> getAttributeNodes() {
return new ArrayList<AttributeNode<?>>( graphDelegate.getGraphNodes() );
}
// AttributeDelegate impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
@SuppressWarnings("unchecked")
public AttributeNodeImpl<?> buildAttributeNode(String attributeName) {
return buildAttributeNode( resolveAttribute( attributeName ) );
}
@SuppressWarnings("unchecked")
private Attribute<T,?> resolveAttribute(String attributeName) {
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;
}
@SuppressWarnings("unchecked")
private <X> Attribute<T, ? extends X> resolveAttribute(String attributeName, Class<? extends X> type) {
final Attribute<T,?> attribute = managedType.getDeclaredAttribute( attributeName );
if ( attribute == null ) {
throw new IllegalArgumentException(
String.format(
"Given attribute name [%s] is not an attribute on this class [%s]",
attributeName,
managedType.getClass().getName()
)
);
}
return (Attribute<T, ? extends X>) attribute;
}
@Override
public AttributeNodeImpl<?> buildAttributeNode(Attribute<T, ?> attribute) {
return new AttributeNodeImpl<Object>( attribute );
}
@Override
public SubgraphImpl buildSubgraph(String attributeName) {
final Attribute<T,?> attribute = resolveAttribute( attributeName );
return new SubgraphImpl( attribute, toManagedType( attribute ) );
}
@SuppressWarnings("unchecked")
private <X> ManagedType<X> toManagedType(Attribute<T, X> attribute) {
if ( attribute.isCollection() ) {
final Type elementType = ( (PluralAttribute) attribute ).getElementType();
if ( ! ManagedType.class.isInstance( elementType ) ) {
throw new IllegalArgumentException(
String.format(
"Specified collection attribute [%s] is not comprised of elements of a ManagedType",
attribute.toString()
)
);
}
return (ManagedType<X>) elementType;
}
else {
final Type type = ( (SingularAttribute) attribute ).getType();
if ( ! ManagedType.class.isInstance( type ) ) {
throw new IllegalArgumentException(
String.format( "Specified attribute [%s] is not a ManagedType" , attribute.toString() )
);
}
return (ManagedType<X>) type;
}
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<X> buildSubgraph(String attributeName, Class<X> type) {
final Attribute<T,X> attribute = (Attribute<T, X>) resolveAttribute( attributeName, type );
return new SubgraphImpl<X>( attribute, toManagedType( attribute ) );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<? extends X> buildSubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return new SubgraphImpl( attribute, toManagedType( attribute ) );
}
@Override
public SubgraphImpl buildKeySubgraph(String attributeName) {
final Attribute<T,?> attribute = resolveAttribute( attributeName );
return new SubgraphImpl( attribute, toManagedType( attribute ), true );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<X> buildKeySubgraph(String attributeName, Class<X> type) {
final Attribute<T,X> attribute = (Attribute<T, X>) resolveAttribute( attributeName, type );
return new SubgraphImpl<X>( attribute, toManagedType( attribute ), true );
}
@Override
@SuppressWarnings("unchecked")
public <X> SubgraphImpl<? extends X> buildKeySubgraph(Attribute<T, X> attribute, Class<? extends X> type) {
return new SubgraphImpl( attribute, toManagedType( attribute ), true );
}
}

View File

@ -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-7plus', jpa: 'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Draft-10',
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.0.Final', jacc: 'org.jboss.spec.javax.security.jacc:jboss-jacc-api_1.4_spec:1.0.0.Final',