/*
 * 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 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.JoinColumnsOrFormulas;
import org.hibernate.annotations.JoinFormula;
import org.hibernate.annotations.common.reflection.XProperty;
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
/** * Do the initial discovery of columns metadata and apply defaults. * Also hosts some convenient methods related to column processing * * @author Emmanuel Bernard */
class ColumnsBuilder { private PropertyHolder propertyHolder; private Nullability nullability; private XProperty property; private PropertyData inferredData; private EntityBinder entityBinder; private Mappings mappings; private Ejb3Column[] columns; private Ejb3JoinColumn[] joinColumns; public ColumnsBuilder( PropertyHolder propertyHolder, Nullability nullability, XProperty property, PropertyData inferredData, EntityBinder entityBinder, Mappings mappings) { this.propertyHolder = propertyHolder; this.nullability = nullability; this.property = property; this.inferredData = inferredData; this.entityBinder = entityBinder; this.mappings = mappings; } 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(), mappings ); } else if ( property.isAnnotationPresent( Columns.class ) ) { Columns anns = property.getAnnotation( Columns.class ); columns = Ejb3Column.buildColumnFromAnnotation( anns.columns(), null, nullability, propertyHolder, inferredData, entityBinder.getSecondaryTables(), mappings ); } //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(), mappings ); } 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(), mappings ); } 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(), mappings ); 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(), mappings ); } return joinColumns; } Ejb3JoinColumn[] buildExplicitJoinColumns(XProperty property, PropertyData inferredData) { //process @JoinColumn(s) before @Column(s) to handle collection of entities properly Ejb3JoinColumn[] joinColumns = null; { JoinColumn[] anns = null; if ( property.isAnnotationPresent( JoinColumn.class ) ) { anns = new JoinColumn[] { property.getAnnotation( JoinColumn.class ) }; } else if ( property.isAnnotationPresent( JoinColumns.class ) ) { JoinColumns ann = property.getAnnotation( JoinColumns.class ); anns = ann.value(); int length = anns.length; if ( length == 0 ) { throw new AnnotationException( "Cannot bind an empty @JoinColumns" ); } } if ( anns != null ) { joinColumns = Ejb3JoinColumn.buildJoinColumns( anns, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappings ); } else if ( property.isAnnotationPresent( JoinColumnsOrFormulas.class ) ) { JoinColumnsOrFormulas ann = property.getAnnotation( JoinColumnsOrFormulas.class ); joinColumns = Ejb3JoinColumn.buildJoinColumnsOrFormulas( ann, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappings ); } else if (property.isAnnotationPresent( JoinFormula.class)) { JoinFormula ann = property.getAnnotation( JoinFormula.class ); joinColumns = new Ejb3JoinColumn[1]; joinColumns[0] = Ejb3JoinColumn.buildJoinFormula( ann, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappings); } } return joinColumns; } Ejb3Column[] overrideColumnFromMapperOrMapsIdProperty(boolean isId) { Ejb3Column[] result = columns; final PropertyData overridingProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId( isId, propertyHolder, property.getName(), mappings ); 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; } }