org.hibernate.cfg.InheritanceState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
The core O/RM functionality as provided by Hibernate
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, 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.cfg;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.Access;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.MappedSuperclass;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.mapping.PersistentClass;
/**
* Some extra data to the inheritance position of a class.
*
* @author Emmanuel Bernard
*/
public class InheritanceState {
private XClass clazz;
/**
* Has sibling (either mappedsuperclass entity)
*/
private boolean hasSiblings = false;
/**
* a mother entity is available
*/
private boolean hasParents = false;
private InheritanceType type;
private boolean isEmbeddableSuperclass = false;
private Map inheritanceStatePerClass;
private List classesToProcessForMappedSuperclass = new ArrayList();
private Mappings mappings;
private AccessType accessType;
private ElementsToProcess elementsToProcess;
private Boolean hasIdClassOrEmbeddedId;
public InheritanceState(XClass clazz, Map inheritanceStatePerClass, Mappings mappings) {
this.setClazz( clazz );
this.mappings = mappings;
this.inheritanceStatePerClass = inheritanceStatePerClass;
extractInheritanceType();
}
private void extractInheritanceType() {
XAnnotatedElement element = getClazz();
Inheritance inhAnn = element.getAnnotation( Inheritance.class );
MappedSuperclass mappedSuperClass = element.getAnnotation( MappedSuperclass.class );
if ( mappedSuperClass != null ) {
setEmbeddableSuperclass( true );
setType( inhAnn == null ? null : inhAnn.strategy() );
}
else {
setType( inhAnn == null ? InheritanceType.SINGLE_TABLE : inhAnn.strategy() );
}
}
boolean hasTable() {
return !hasParents() || !InheritanceType.SINGLE_TABLE.equals( getType() );
}
boolean hasDenormalizedTable() {
return hasParents() && InheritanceType.TABLE_PER_CLASS.equals( getType() );
}
public static InheritanceState getInheritanceStateOfSuperEntity(
XClass clazz, Map states
) {
XClass superclass = clazz;
do {
superclass = superclass.getSuperclass();
InheritanceState currentState = states.get( superclass );
if ( currentState != null && !currentState.isEmbeddableSuperclass() ) {
return currentState;
}
}
while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) );
return null;
}
public static InheritanceState getSuperclassInheritanceState(XClass clazz, Map states) {
XClass superclass = clazz;
do {
superclass = superclass.getSuperclass();
InheritanceState currentState = states.get( superclass );
if ( currentState != null ) {
return currentState;
}
}
while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) );
return null;
}
public XClass getClazz() {
return clazz;
}
public void setClazz(XClass clazz) {
this.clazz = clazz;
}
public boolean hasSiblings() {
return hasSiblings;
}
public void setHasSiblings(boolean hasSiblings) {
this.hasSiblings = hasSiblings;
}
public boolean hasParents() {
return hasParents;
}
public void setHasParents(boolean hasParents) {
this.hasParents = hasParents;
}
public InheritanceType getType() {
return type;
}
public void setType(InheritanceType type) {
this.type = type;
}
public boolean isEmbeddableSuperclass() {
return isEmbeddableSuperclass;
}
public void setEmbeddableSuperclass(boolean embeddableSuperclass) {
isEmbeddableSuperclass = embeddableSuperclass;
}
void postProcess(PersistentClass persistenceClass, EntityBinder entityBinder) {
//make sure we run elements to process
getElementsToProcess();
addMappedSuperClassInMetadata( persistenceClass );
entityBinder.setPropertyAccessType( accessType );
}
public XClass getClassWithIdClass(boolean evenIfSubclass) {
if ( !evenIfSubclass && hasParents() ) {
return null;
}
if ( clazz.isAnnotationPresent( IdClass.class ) ) {
return clazz;
}
else {
InheritanceState state = InheritanceState.getSuperclassInheritanceState( clazz, inheritanceStatePerClass );
if ( state != null ) {
return state.getClassWithIdClass( true );
}
else {
return null;
}
}
}
public Boolean hasIdClassOrEmbeddedId() {
if ( hasIdClassOrEmbeddedId == null ) {
hasIdClassOrEmbeddedId = false;
if ( getClassWithIdClass( true ) != null ) {
hasIdClassOrEmbeddedId = true;
}
else {
final ElementsToProcess process = getElementsToProcess();
for ( PropertyData property : process.getElements() ) {
if ( property.getProperty().isAnnotationPresent( EmbeddedId.class ) ) {
hasIdClassOrEmbeddedId = true;
break;
}
}
}
}
return hasIdClassOrEmbeddedId;
}
/*
* Get the annotated elements and determine access type from hierarchy, guessing from @Id or @EmbeddedId presence if not
* specified.
* Change EntityBinder by side effect
*/
public ElementsToProcess getElementsToProcess() {
if ( elementsToProcess == null ) {
InheritanceState inheritanceState = inheritanceStatePerClass.get( clazz );
assert !inheritanceState.isEmbeddableSuperclass();
getMappedSuperclassesTillNextEntityOrdered();
accessType = determineDefaultAccessType();
ArrayList elements = new ArrayList();
int deep = classesToProcessForMappedSuperclass.size();
int idPropertyCount = 0;
for ( int index = 0; index < deep; index++ ) {
PropertyContainer propertyContainer = new PropertyContainer(
classesToProcessForMappedSuperclass.get(
index
), clazz
);
int currentIdPropertyCount = AnnotationBinder.addElementsOfClass(
elements, accessType, propertyContainer, mappings
);
idPropertyCount += currentIdPropertyCount;
}
if ( idPropertyCount == 0 && !inheritanceState.hasParents() ) {
throw new AnnotationException( "No identifier specified for entity: " + clazz.getName() );
}
elements.trimToSize();
elementsToProcess = new ElementsToProcess( elements, idPropertyCount );
}
return elementsToProcess;
}
private AccessType determineDefaultAccessType() {
for (XClass xclass = clazz; xclass != null; xclass = xclass.getSuperclass()) {
if ((xclass.getSuperclass() == null || Object.class.getName().equals(xclass.getSuperclass().getName()))
&& (xclass.isAnnotationPresent(Entity.class) || xclass.isAnnotationPresent(MappedSuperclass.class))
&& xclass.isAnnotationPresent(Access.class))
return AccessType.getAccessStrategy(xclass.getAnnotation(Access.class).value());
}
// Guess from identifier.
// FIX: Shouldn't this be determined by the first attribute (i.e., field or property) with annotations, but without an
// explicit Access annotation, according to JPA 2.0 spec 2.3.1: Default Access Type?
for (XClass xclass = clazz; xclass != null && !Object.class.getName().equals(xclass.getName()); xclass = xclass.getSuperclass()) {
if ( xclass.isAnnotationPresent( Entity.class ) || xclass.isAnnotationPresent( MappedSuperclass.class ) ) {
for ( XProperty prop : xclass.getDeclaredProperties( AccessType.PROPERTY.getType() ) ) {
final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class );
if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) {
return AccessType.PROPERTY;
}
}
for ( XProperty prop : xclass.getDeclaredProperties( AccessType.FIELD.getType() ) ) {
final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class );
if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) {
return AccessType.FIELD;
}
}
}
}
throw new AnnotationException( "No identifier specified for entity: " + clazz );
}
private void getMappedSuperclassesTillNextEntityOrdered() {
//ordered to allow proper messages on properties subclassing
XClass currentClassInHierarchy = clazz;
InheritanceState superclassState;
do {
classesToProcessForMappedSuperclass.add( 0, currentClassInHierarchy );
XClass superClass = currentClassInHierarchy;
do {
superClass = superClass.getSuperclass();
superclassState = inheritanceStatePerClass.get( superClass );
}
while ( superClass != null
&& !mappings.getReflectionManager().equals( superClass, Object.class ) && superclassState == null );
currentClassInHierarchy = superClass;
}
while ( superclassState != null && superclassState.isEmbeddableSuperclass() );
}
private void addMappedSuperClassInMetadata(PersistentClass persistentClass) {
//add @MappedSuperclass in the metadata
// classes from 0 to n-1 are @MappedSuperclass and should be linked
org.hibernate.mapping.MappedSuperclass mappedSuperclass = null;
final InheritanceState superEntityState =
InheritanceState.getInheritanceStateOfSuperEntity( clazz, inheritanceStatePerClass );
PersistentClass superEntity =
superEntityState != null ?
mappings.getClass( superEntityState.getClazz().getName() ) :
null;
final int lastMappedSuperclass = classesToProcessForMappedSuperclass.size() - 1;
for ( int index = 0; index < lastMappedSuperclass; index++ ) {
org.hibernate.mapping.MappedSuperclass parentSuperclass = mappedSuperclass;
final Class> type = mappings.getReflectionManager()
.toClass( classesToProcessForMappedSuperclass.get( index ) );
//add MAppedSuperclass if not already there
mappedSuperclass = mappings.getMappedSuperclass( type );
if ( mappedSuperclass == null ) {
mappedSuperclass = new org.hibernate.mapping.MappedSuperclass( parentSuperclass, superEntity );
mappedSuperclass.setMappedClass( type );
mappings.addMappedSuperclass( type, mappedSuperclass );
}
}
if ( mappedSuperclass != null ) {
persistentClass.setSuperMappedSuperclass( mappedSuperclass );
}
}
static final class ElementsToProcess {
private final List properties;
private final int idPropertyCount;
public List getElements() {
return properties;
}
public int getIdPropertyCount() {
return idPropertyCount;
}
private ElementsToProcess(List properties, int idPropertyCount) {
this.properties = properties;
this.idPropertyCount = idPropertyCount;
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy