All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.jpa.graph.internal.AttributeNodeImpl Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.jpa.graph.internal;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.AttributeNode;
import javax.persistence.Subgraph;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.ManagedType;
import javax.persistence.metamodel.PluralAttribute;

import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.spi.HibernateEntityManagerFactoryAware;
import org.hibernate.metamodel.internal.Helper;
import org.hibernate.metamodel.internal.PluralAttributeImpl;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;

/**
 * Hibernate implementation of the JPA AttributeNode contract
 *
 * @author Steve Ebersole
 */
public class AttributeNodeImpl implements AttributeNode, AttributeNodeImplementor, HibernateEntityManagerFactoryAware {
	private final SessionFactoryImplementor sessionFactory;
	private final Attribute attribute;
	private final ManagedType managedType;

	private Map subgraphMap;
	private Map keySubgraphMap;

	@SuppressWarnings("WeakerAccess")
	public  AttributeNodeImpl(
			SessionFactoryImplementor sessionFactory,
			ManagedType managedType,
			Attribute attribute) {
		this.sessionFactory = sessionFactory;
		this.managedType = managedType;
		this.attribute = attribute;
	}

	/**
	 * Intended only for use from {@link #makeImmutableCopy()}
	 */
	private AttributeNodeImpl(
			SessionFactoryImplementor sessionFactory,
			ManagedType managedType,
			Attribute attribute,
			Map subgraphMap,
			Map keySubgraphMap) {
		this.sessionFactory = sessionFactory;
		this.managedType = managedType;
		this.attribute = attribute;
		this.subgraphMap = subgraphMap;
		this.keySubgraphMap = keySubgraphMap;
	}

	@Override
	public SessionFactoryImplementor getFactory() {
		return sessionFactory;
	}

	private SessionFactoryImplementor sessionFactory() {
		return getFactory();
	}

	@Override
	public Attribute getAttribute() {
		return attribute;
	}

	@SuppressWarnings("WeakerAccess")
	public String getRegistrationName() {
		return getAttributeName();
	}

	@Override
	public String getAttributeName() {
		return attribute.getName();
	}

	@Override
	public Map getSubgraphs() {
		return subgraphMap == null ? Collections.emptyMap() : subgraphMap;
	}

	@Override
	public Map getKeySubgraphs() {
		return keySubgraphMap == null ? Collections.emptyMap() : keySubgraphMap;
	}

	@SuppressWarnings("unchecked")
	public  SubgraphImpl makeSubgraph() {
		return (SubgraphImpl) internalMakeSubgraph( null );
	}

	@SuppressWarnings("WeakerAccess")
	public  SubgraphImpl makeSubgraph(Class type) {
		return internalMakeSubgraph( type );
	}

	@SuppressWarnings("unchecked")
	private  SubgraphImpl internalMakeSubgraph(Class 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<>();
		}

		final Helper.AttributeSource attributeSource = Helper.resolveAttributeSource( sessionFactory(), managedType );
		final AssociationType attributeType = (AssociationType) attributeSource.findType( attribute.getName() );

		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()
							)
					);
				}
			}
		}
		
		ManagedType managedType = null;
		try {
			managedType = sessionFactory.getMetamodel().entity( type.getName() );
		}
		catch (IllegalArgumentException e) {
			// do nothing
		}
		if (managedType == null) {
			managedType = attribute.getDeclaringType();
		}

		final SubgraphImpl subgraph = new SubgraphImpl<>( this.sessionFactory, managedType, 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() );
	}

	@SuppressWarnings("unchecked")
	public  SubgraphImpl makeKeySubgraph() {
		return (SubgraphImpl) internalMakeKeySubgraph( null );
	}

	@SuppressWarnings("WeakerAccess")
	public  SubgraphImpl makeKeySubgraph(Class type) {
		return internalMakeKeySubgraph( type );
	}

	@SuppressWarnings("unchecked")
	private  SubgraphImpl internalMakeKeySubgraph(Class 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<>();
		}

		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.sessionFactory, attribute.getDeclaringType(), type );
		keySubgraphMap.put( type, subgraph );
		return subgraph;
	}

	@Override
	public AttributeNodeImpl makeImmutableCopy() {
		return new AttributeNodeImpl<>(
				this.sessionFactory,
				this.managedType,
				this.attribute,
				makeSafeMapCopy( subgraphMap ),
				makeSafeMapCopy( keySubgraphMap )
		);
	}

	private static Map makeSafeMapCopy(Map subgraphMap) {
		if ( subgraphMap == null ) {
			return null;
		}

		final int properSize = CollectionHelper.determineProperSizing( subgraphMap );
		final HashMap copy = new HashMap<>( properSize );
		for ( Map.Entry subgraphEntry : subgraphMap.entrySet() ) {
			copy.put(
					subgraphEntry.getKey(),
					( ( SubgraphImpl ) subgraphEntry.getValue() ).makeImmutableCopy()
			);
		}
		return copy;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy