/*
 * 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.cfg;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;

import org.hibernate.AnnotationException;
import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.JoinColumnOrFormula;
import org.hibernate.annotations.JoinColumnsOrFormulas;
import org.hibernate.annotations.JoinFormula;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.cfg.annotations.Nullability;
import org.hibernate.internal.util.StringHelper;

Do the initial discovery of columns metadata and apply defaults. Also hosts some convenient methods related to column processing
Author:Emmanuel Bernard, Brett Meyer
/** * Do the initial discovery of columns metadata and apply defaults. * Also hosts some convenient methods related to column processing * * @author Emmanuel Bernard * @author Brett Meyer */
class ColumnsBuilder { private PropertyHolder propertyHolder; private Nullability nullability; private XProperty property; private PropertyData inferredData; private EntityBinder entityBinder; private MetadataBuildingContext buildingContext; private Ejb3Column[] columns; private Ejb3JoinColumn[] joinColumns; public ColumnsBuilder( PropertyHolder propertyHolder, Nullability nullability, XProperty property, PropertyData inferredData, EntityBinder entityBinder, MetadataBuildingContext buildingContext) { this.propertyHolder = propertyHolder; this.nullability = nullability; this.property = property; this.inferredData = inferredData; this.entityBinder = entityBinder; this.buildingContext = buildingContext; } public Ejb3Column[] getColumns() { return columns; } public Ejb3JoinColumn[] getJoinColumns() { return joinColumns; } public ColumnsBuilder extractMetadata() { columns = null; joinColumns = buildExplicitJoinColumns(property, inferredData); if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent( Formula.class ) ) { Column ann = property.getAnnotation( Column.class ); Formula formulaAnn = property.getAnnotation( Formula.class ); columns = Ejb3Column.buildColumnFromAnnotation( new Column[] { ann }, formulaAnn, nullability, propertyHolder, inferredData, entityBinder.getSecondaryTables(), buildingContext ); } else if ( property.isAnnotationPresent( Columns.class ) ) { Columns anns = property.getAnnotation( Columns.class ); columns = Ejb3Column.buildColumnFromAnnotation( anns.columns(), null, nullability, propertyHolder, inferredData, entityBinder.getSecondaryTables(), buildingContext ); } //set default values if needed if ( joinColumns == null && ( property.isAnnotationPresent( ManyToOne.class ) || property.isAnnotationPresent( OneToOne.class ) ) ) { joinColumns = buildDefaultJoinColumnsForXToOne(property, inferredData); } else if ( joinColumns == null && ( property.isAnnotationPresent( OneToMany.class ) || property.isAnnotationPresent( ElementCollection.class ) ) ) { OneToMany oneToMany = property.getAnnotation( OneToMany.class ); String mappedBy = oneToMany != null ? oneToMany.mappedBy() : ""; joinColumns = Ejb3JoinColumn.buildJoinColumns( null, mappedBy, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext ); } else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) { throw new AnnotationException( "@Any requires an explicit @JoinColumn(s): " + BinderHelper.getPath( propertyHolder, inferredData ) ); } if ( columns == null && !property.isAnnotationPresent( ManyToMany.class ) ) { //useful for collection of embedded elements columns = Ejb3Column.buildColumnFromAnnotation( null, null, nullability, propertyHolder, inferredData, entityBinder.getSecondaryTables(), buildingContext ); } if ( nullability == Nullability.FORCED_NOT_NULL ) { //force columns to not null for (Ejb3Column col : columns ) { col.forceNotNull(); } } return this; } Ejb3JoinColumn[] buildDefaultJoinColumnsForXToOne(XProperty property, PropertyData inferredData) { Ejb3JoinColumn[] joinColumns; JoinTable joinTableAnn = propertyHolder.getJoinTable( property ); if ( joinTableAnn != null ) { joinColumns = Ejb3JoinColumn.buildJoinColumns( joinTableAnn.inverseJoinColumns(), null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext ); if ( StringHelper.isEmpty( joinTableAnn.name() ) ) { throw new AnnotationException( "JoinTable.name() on a @ToOne association has to be explicit: " + BinderHelper.getPath( propertyHolder, inferredData ) ); } } else { OneToOne oneToOneAnn = property.getAnnotation( OneToOne.class ); String mappedBy = oneToOneAnn != null ? oneToOneAnn.mappedBy() : null; joinColumns = Ejb3JoinColumn.buildJoinColumns( null, mappedBy, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext ); } return joinColumns; } Ejb3JoinColumn[] buildExplicitJoinColumns(XProperty property, PropertyData inferredData) { //process @JoinColumn(s) before @Column(s) to handle collection of entities properly JoinColumn[] joinColumnAnnotations = null; if ( property.isAnnotationPresent( JoinColumn.class ) ) { joinColumnAnnotations = new JoinColumn[] { property.getAnnotation( JoinColumn.class ) }; } else if ( property.isAnnotationPresent( JoinColumns.class ) ) { JoinColumns joinColumnAnnotation = property.getAnnotation( JoinColumns.class ); joinColumnAnnotations = joinColumnAnnotation.value(); int length = joinColumnAnnotations.length; if ( length == 0 ) { throw new AnnotationException( "Cannot bind an empty @JoinColumns" ); } } if ( joinColumnAnnotations != null ) { return Ejb3JoinColumn.buildJoinColumns( joinColumnAnnotations, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext ); } JoinColumnOrFormula[] joinColumnOrFormulaAnnotations = null; if ( property.isAnnotationPresent( JoinColumnOrFormula.class ) ) { joinColumnOrFormulaAnnotations = new JoinColumnOrFormula[] { property.getAnnotation( JoinColumnOrFormula.class ) }; } else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) { JoinColumnsOrFormulas joinColumnsOrFormulasAnnotations = property.getAnnotation( JoinColumnsOrFormulas.class ); joinColumnOrFormulaAnnotations = joinColumnsOrFormulasAnnotations.value(); int length = joinColumnOrFormulaAnnotations.length; if ( length == 0 ) { throw new AnnotationException( "Cannot bind an empty @JoinColumnsOrFormulas" ); } } if (joinColumnOrFormulaAnnotations != null) { return Ejb3JoinColumn.buildJoinColumnsOrFormulas( joinColumnOrFormulaAnnotations, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext ); } if (property.isAnnotationPresent( JoinFormula.class)) { JoinFormula ann = property.getAnnotation( JoinFormula.class ); Ejb3JoinColumn[] ejb3JoinColumns = new Ejb3JoinColumn[1]; ejb3JoinColumns[0] = Ejb3JoinColumn.buildJoinFormula( ann, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext ); return ejb3JoinColumns; } return null; } Ejb3Column[] overrideColumnFromMapperOrMapsIdProperty(boolean isId) { Ejb3Column[] result = columns; final PropertyData overridingProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), buildingContext ); if ( overridingProperty != null ) { result = buildExcplicitOrDefaultJoinColumn( overridingProperty ); } return result; }
useful to override a column either by @MapsId or by @IdClass
/** * useful to override a column either by @MapsId or by @IdClass */
Ejb3Column[] buildExcplicitOrDefaultJoinColumn(PropertyData overridingProperty) { Ejb3Column[] result; result = buildExplicitJoinColumns( overridingProperty.getProperty(), overridingProperty ); if (result == null) { result = buildDefaultJoinColumnsForXToOne( overridingProperty.getProperty(), overridingProperty); } return result; } }