use of jakarta.persistence.JoinColumn in project hibernate-orm by hibernate.
the class AnnotationBinder method bindCollection.
private static void bindCollection(PropertyHolder propertyHolder, Nullability nullability, PropertyData inferredData, Map<String, IdentifierGeneratorDefinition> classGenerators, EntityBinder entityBinder, boolean isIdentifierMapper, MetadataBuildingContext context, Map<XClass, InheritanceState> inheritanceStatePerClass, XProperty property, AnnotatedJoinColumn[] joinColumns) {
OneToMany oneToManyAnn = property.getAnnotation(OneToMany.class);
ManyToMany manyToManyAnn = property.getAnnotation(ManyToMany.class);
ElementCollection elementCollectionAnn = property.getAnnotation(ElementCollection.class);
if ((oneToManyAnn != null || manyToManyAnn != null || elementCollectionAnn != null) && isToManyAssociationWithinEmbeddableCollection(propertyHolder)) {
throw new AnnotationException("@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection: " + BinderHelper.getPath(propertyHolder, inferredData));
}
if (property.isAnnotationPresent(OrderColumn.class) && manyToManyAnn != null && !manyToManyAnn.mappedBy().isEmpty()) {
throw new AnnotationException("Explicit @OrderColumn on inverse side of @ManyToMany is illegal: " + BinderHelper.getPath(propertyHolder, inferredData));
}
final IndexColumn indexColumn = IndexColumn.fromAnnotations(property.getAnnotation(OrderColumn.class), property.getAnnotation(org.hibernate.annotations.IndexColumn.class), property.getAnnotation(ListIndexBase.class), propertyHolder, inferredData, entityBinder.getSecondaryTables(), context);
CollectionBinder collectionBinder = getCollectionBinder(property, hasMapKeyAnnotation(property), context);
collectionBinder.setIndexColumn(indexColumn);
collectionBinder.setMapKey(property.getAnnotation(MapKey.class));
collectionBinder.setPropertyName(inferredData.getPropertyName());
collectionBinder.setBatchSize(property.getAnnotation(BatchSize.class));
collectionBinder.setJpaOrderBy(property.getAnnotation(jakarta.persistence.OrderBy.class));
collectionBinder.setSqlOrderBy(getOverridableAnnotation(property, OrderBy.class, context));
collectionBinder.setNaturalSort(property.getAnnotation(SortNatural.class));
collectionBinder.setComparatorSort(property.getAnnotation(SortComparator.class));
collectionBinder.setCache(property.getAnnotation(Cache.class));
collectionBinder.setPropertyHolder(propertyHolder);
Cascade hibernateCascade = property.getAnnotation(Cascade.class);
NotFound notFound = property.getAnnotation(NotFound.class);
collectionBinder.setIgnoreNotFound(notFound != null && notFound.action() == NotFoundAction.IGNORE);
collectionBinder.setCollectionType(inferredData.getProperty().getElementClass());
collectionBinder.setAccessType(inferredData.getDefaultAccess());
AnnotatedColumn[] elementColumns;
// do not use "element" if you are a JPA 2 @ElementCollection, only for legacy Hibernate mappings
PropertyData virtualProperty = property.isAnnotationPresent(ElementCollection.class) ? inferredData : new WrappedInferredData(inferredData, "element");
Comment comment = property.getAnnotation(Comment.class);
if (property.isAnnotationPresent(Column.class)) {
elementColumns = buildColumnFromAnnotation(property.getAnnotation(Column.class), comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
} else if (property.isAnnotationPresent(Formula.class)) {
elementColumns = buildFormulaFromAnnotation(getOverridableAnnotation(property, Formula.class, context), comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
} else if (property.isAnnotationPresent(Columns.class)) {
elementColumns = buildColumnsFromAnnotations(property.getAnnotation(Columns.class).columns(), comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
} else {
elementColumns = buildColumnFromNoAnnotation(comment, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
}
JoinColumn[] joinKeyColumns = mapKeyColumns(propertyHolder, inferredData, entityBinder, context, property, collectionBinder, comment);
AnnotatedJoinColumn[] mapJoinColumns = buildJoinColumnsWithDefaultColumnSuffix(joinKeyColumns, comment, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), "_KEY", context);
collectionBinder.setMapKeyManyToManyColumns(mapJoinColumns);
// potential element
collectionBinder.setEmbedded(property.isAnnotationPresent(Embedded.class));
collectionBinder.setElementColumns(elementColumns);
collectionBinder.setProperty(property);
// TODO enhance exception with @ManyToAny and @CollectionOfElements
if (oneToManyAnn != null && manyToManyAnn != null) {
throw new AnnotationException("@OneToMany and @ManyToMany on the same property is not allowed: " + propertyHolder.getEntityName() + "." + inferredData.getPropertyName());
}
String mappedBy = null;
ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager();
if (oneToManyAnn != null) {
for (AnnotatedJoinColumn column : joinColumns) {
if (column.isSecondary()) {
throw new NotYetImplementedException("Collections having FK in secondary table");
}
}
collectionBinder.setFkJoinColumns(joinColumns);
mappedBy = oneToManyAnn.mappedBy();
// noinspection unchecked
collectionBinder.setTargetEntity(reflectionManager.toXClass(oneToManyAnn.targetEntity()));
collectionBinder.setCascadeStrategy(getCascadeStrategy(oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval(), false));
collectionBinder.setOneToMany(true);
} else if (elementCollectionAnn != null) {
for (AnnotatedJoinColumn column : joinColumns) {
if (column.isSecondary()) {
throw new NotYetImplementedException("Collections having FK in secondary table");
}
}
collectionBinder.setFkJoinColumns(joinColumns);
mappedBy = "";
final Class<?> targetElement = elementCollectionAnn.targetClass();
collectionBinder.setTargetEntity(reflectionManager.toXClass(targetElement));
// collectionBinder.setCascadeStrategy( getCascadeStrategy( embeddedCollectionAnn.cascade(), hibernateCascade ) );
collectionBinder.setOneToMany(true);
} else if (manyToManyAnn != null) {
mappedBy = manyToManyAnn.mappedBy();
// noinspection unchecked
collectionBinder.setTargetEntity(reflectionManager.toXClass(manyToManyAnn.targetEntity()));
collectionBinder.setCascadeStrategy(getCascadeStrategy(manyToManyAnn.cascade(), hibernateCascade, false, false));
collectionBinder.setOneToMany(false);
} else if (property.isAnnotationPresent(ManyToAny.class)) {
mappedBy = "";
collectionBinder.setTargetEntity(reflectionManager.toXClass(void.class));
collectionBinder.setCascadeStrategy(getCascadeStrategy(null, hibernateCascade, false, false));
collectionBinder.setOneToMany(false);
}
collectionBinder.setMappedBy(mappedBy);
bindJoinedTableAssociation(property, context, entityBinder, collectionBinder, propertyHolder, inferredData, mappedBy);
OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action();
collectionBinder.setCascadeDeleteEnabled(onDeleteCascade);
if (isIdentifierMapper) {
collectionBinder.setInsertable(false);
collectionBinder.setUpdatable(false);
}
if (property.isAnnotationPresent(CollectionId.class)) {
// do not compute the generators unless necessary
HashMap<String, IdentifierGeneratorDefinition> localGenerators = new HashMap<>(classGenerators);
localGenerators.putAll(buildGenerators(property, context));
collectionBinder.setLocalGenerators(localGenerators);
}
collectionBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
collectionBinder.setDeclaringClass(inferredData.getDeclaringClass());
collectionBinder.bind();
}
use of jakarta.persistence.JoinColumn in project hibernate-orm by hibernate.
the class AnnotationBinder method bindJoinedTableAssociation.
// TODO move that to collection binder?
private static void bindJoinedTableAssociation(XProperty property, MetadataBuildingContext buildingContext, EntityBinder entityBinder, CollectionBinder collectionBinder, PropertyHolder propertyHolder, PropertyData inferredData, String mappedBy) {
TableBinder associationTableBinder = new TableBinder();
JoinColumn[] annJoins;
JoinColumn[] annInverseJoins;
JoinTable assocTable = propertyHolder.getJoinTable(property);
CollectionTable collectionTable = property.getAnnotation(CollectionTable.class);
if (assocTable != null || collectionTable != null) {
final String catalog;
final String schema;
final String tableName;
final UniqueConstraint[] uniqueConstraints;
final JoinColumn[] joins;
final JoinColumn[] inverseJoins;
final jakarta.persistence.Index[] jpaIndexes;
// JPA 2 has priority
if (collectionTable != null) {
catalog = collectionTable.catalog();
schema = collectionTable.schema();
tableName = collectionTable.name();
uniqueConstraints = collectionTable.uniqueConstraints();
joins = collectionTable.joinColumns();
inverseJoins = null;
jpaIndexes = collectionTable.indexes();
} else {
catalog = assocTable.catalog();
schema = assocTable.schema();
tableName = assocTable.name();
uniqueConstraints = assocTable.uniqueConstraints();
joins = assocTable.joinColumns();
inverseJoins = assocTable.inverseJoinColumns();
jpaIndexes = assocTable.indexes();
}
collectionBinder.setExplicitAssociationTable(true);
if (jpaIndexes != null && jpaIndexes.length > 0) {
associationTableBinder.setJpaIndex(jpaIndexes);
}
if (!BinderHelper.isEmptyAnnotationValue(schema)) {
associationTableBinder.setSchema(schema);
}
if (!BinderHelper.isEmptyAnnotationValue(catalog)) {
associationTableBinder.setCatalog(catalog);
}
if (!BinderHelper.isEmptyAnnotationValue(tableName)) {
associationTableBinder.setName(tableName);
}
associationTableBinder.setUniqueConstraints(uniqueConstraints);
associationTableBinder.setJpaIndex(jpaIndexes);
// set check constraint in the second pass
annJoins = joins.length == 0 ? null : joins;
annInverseJoins = inverseJoins == null || inverseJoins.length == 0 ? null : inverseJoins;
} else {
annJoins = null;
annInverseJoins = null;
}
AnnotatedJoinColumn[] joinColumns = buildJoinTableJoinColumns(annJoins, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappedBy, buildingContext);
AnnotatedJoinColumn[] inverseJoinColumns = buildJoinTableJoinColumns(annInverseJoins, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappedBy, buildingContext);
associationTableBinder.setBuildingContext(buildingContext);
collectionBinder.setTableBinder(associationTableBinder);
collectionBinder.setJoinColumns(joinColumns);
collectionBinder.setInverseJoinColumns(inverseJoinColumns);
}
use of jakarta.persistence.JoinColumn in project hibernate-orm by hibernate.
the class AnnotationBinder method mapKeyColumns.
private static JoinColumn[] mapKeyColumns(PropertyHolder propertyHolder, PropertyData inferredData, EntityBinder entityBinder, MetadataBuildingContext context, XProperty property, CollectionBinder collectionBinder, Comment comment) {
Column[] keyColumns = property.isAnnotationPresent(MapKeyColumn.class) ? new Column[] { new MapKeyColumnDelegator(property.getAnnotation(MapKeyColumn.class)) } : null;
AnnotatedColumn[] mapColumns = buildColumnsFromAnnotations(keyColumns, comment, Nullability.FORCED_NOT_NULL, propertyHolder, inferredData, "_KEY", entityBinder.getSecondaryTables(), context);
collectionBinder.setMapKeyColumns(mapColumns);
JoinColumn[] joinKeyColumns = null;
if (property.isAnnotationPresent(MapKeyJoinColumns.class)) {
final MapKeyJoinColumn[] mapKeyJoinColumns = property.getAnnotation(MapKeyJoinColumns.class).value();
joinKeyColumns = new JoinColumn[mapKeyJoinColumns.length];
int index = 0;
for (MapKeyJoinColumn joinColumn : mapKeyJoinColumns) {
joinKeyColumns[index] = new MapKeyJoinColumnDelegator(joinColumn);
index++;
}
if (property.isAnnotationPresent(MapKeyJoinColumn.class)) {
throw new AnnotationException("@MapKeyJoinColumn and @MapKeyJoinColumns used on the same property: " + BinderHelper.getPath(propertyHolder, inferredData));
}
} else if (property.isAnnotationPresent(MapKeyJoinColumn.class)) {
joinKeyColumns = new JoinColumn[] { new MapKeyJoinColumnDelegator(property.getAnnotation(MapKeyJoinColumn.class)) };
}
return joinKeyColumns;
}
use of jakarta.persistence.JoinColumn in project hibernate-orm by hibernate.
the class AnnotationBinder method bindManyToOne.
private static void bindManyToOne(PropertyHolder propertyHolder, PropertyData inferredData, boolean isIdentifierMapper, boolean inSecondPass, MetadataBuildingContext context, XProperty property, AnnotatedJoinColumn[] joinColumns, PropertyBinder propertyBinder, boolean forcePersist) {
ManyToOne ann = property.getAnnotation(ManyToOne.class);
// check validity
if (property.isAnnotationPresent(Column.class) || property.isAnnotationPresent(Columns.class)) {
throw new AnnotationException("@Column(s) not allowed on a @ManyToOne property: " + BinderHelper.getPath(propertyHolder, inferredData));
}
Cascade hibernateCascade = property.getAnnotation(Cascade.class);
NotFound notFound = property.getAnnotation(NotFound.class);
boolean ignoreNotFound = notFound != null && notFound.action() == NotFoundAction.IGNORE;
matchIgnoreNotFoundWithFetchType(propertyHolder.getEntityName(), property.getName(), ignoreNotFound, ann.fetch());
OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
JoinTable assocTable = propertyHolder.getJoinTable(property);
if (assocTable != null) {
Join join = propertyHolder.addJoin(assocTable, false);
for (AnnotatedJoinColumn joinColumn : joinColumns) {
joinColumn.setExplicitTableName(join.getTable().getName());
}
}
// MapsId means the columns belong to the pk;
// A @MapsId association (obviously) must be non-null when the entity is first persisted.
// If a @MapsId association is not mapped with @NotFound(IGNORE), then the association
// is mandatory (even if the association has optional=true).
// If a @MapsId association has optional=true and is mapped with @NotFound(IGNORE) then
// the association is optional.
final boolean mandatory = !ann.optional() || property.isAnnotationPresent(Id.class) || property.isAnnotationPresent(MapsId.class) && !ignoreNotFound;
bindManyToOne(getCascadeStrategy(ann.cascade(), hibernateCascade, false, forcePersist), joinColumns, !mandatory, ignoreNotFound, onDeleteAnn != null && OnDeleteAction.CASCADE == onDeleteAnn.action(), ToOneBinder.getTargetEntity(inferredData, context), propertyHolder, inferredData, false, isIdentifierMapper, inSecondPass, propertyBinder, context);
}
use of jakarta.persistence.JoinColumn in project hibernate-orm by hibernate.
the class ColumnsBuilder method buildExplicitJoinColumns.
AnnotatedJoinColumn[] 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 AnnotatedJoinColumn.buildJoinColumns(joinColumnAnnotations, property.getAnnotation(Comment.class), 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 AnnotatedJoinColumn.buildJoinColumnsOrFormulas(joinColumnOrFormulaAnnotations, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext);
}
if (property.isAnnotationPresent(JoinFormula.class)) {
JoinFormula ann = getOverridableAnnotation(property, JoinFormula.class, buildingContext);
AnnotatedJoinColumn[] annotatedJoinColumns = new AnnotatedJoinColumn[1];
annotatedJoinColumns[0] = AnnotatedJoinColumn.buildJoinFormula(ann, null, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), buildingContext);
return annotatedJoinColumns;
}
return null;
}
Aggregations