use of jakarta.persistence.ManyToMany 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.ManyToMany in project hibernate-orm by hibernate.
the class JPAXMLOverriddenAnnotationReader method getManyToMany.
/**
* @see #getOneToOne(List, XMLContext.Default)
* @see #getElementCollection(List, XMLContext.Default)
*/
private void getManyToMany(List<Annotation> annotationList, XMLContext.Default defaults) {
Class<ManyToMany> annotationType = ManyToMany.class;
List<JaxbManyToMany> elements = elementsForProperty.getManyToMany();
for (JaxbManyToMany element : elements) {
AnnotationDescriptor ad = new AnnotationDescriptor(annotationType);
addTargetClass(element.getTargetEntity(), ad, "target-entity", defaults);
getFetchType(ad, element.getFetch());
getCascades(ad, element.getCascade(), defaults);
getJoinTable(annotationList, element, defaults);
copyAttribute(ad, "mapped-by", element.getMappedBy(), false);
annotationList.add(AnnotationFactory.create(ad));
getOrderBy(annotationList, element.getOrderBy());
getMapKey(annotationList, element.getMapKey());
getMapKeyClass(annotationList, element.getMapKeyClass(), defaults);
getMapKeyColumn(annotationList, element.getMapKeyColumn());
getOrderColumn(annotationList, element.getOrderColumn());
getMapKeyTemporal(annotationList, element.getMapKeyTemporal());
getMapKeyEnumerated(annotationList, element.getMapKeyEnumerated());
Annotation annotation = getMapKeyAttributeOverrides(element.getMapKeyAttributeOverride(), defaults);
addIfNotNull(annotationList, annotation);
getMapKeyJoinColumns(annotationList, element.getMapKeyJoinColumn());
getAccessType(annotationList, element.getAccess());
}
afterGetAssociation(annotationType, annotationList, defaults);
}
use of jakarta.persistence.ManyToMany in project hibernate-orm by hibernate.
the class JPAXMLOverriddenAnnotationReader method overridesDefaultsInJoinTable.
private JoinTable overridesDefaultsInJoinTable(Annotation annotation, XMLContext.Default defaults) {
// no element but might have some default or some annotation
boolean defaultToJoinTable = !(isPhysicalAnnotationPresent(JoinColumn.class) || isPhysicalAnnotationPresent(JoinColumns.class));
final Class<? extends Annotation> annotationClass = annotation.annotationType();
defaultToJoinTable = defaultToJoinTable && ((annotationClass == ManyToMany.class && StringHelper.isEmpty(((ManyToMany) annotation).mappedBy())) || (annotationClass == OneToMany.class && StringHelper.isEmpty(((OneToMany) annotation).mappedBy())) || (annotationClass == ElementCollection.class));
final Class<JoinTable> annotationType = JoinTable.class;
if (defaultToJoinTable && (StringHelper.isNotEmpty(defaults.getCatalog()) || StringHelper.isNotEmpty(defaults.getSchema()))) {
AnnotationDescriptor ad = new AnnotationDescriptor(annotationType);
if (defaults.canUseJavaAnnotations()) {
JoinTable table = getPhysicalAnnotation(annotationType);
if (table != null) {
ad.setValue("name", table.name());
ad.setValue("schema", table.schema());
ad.setValue("catalog", table.catalog());
ad.setValue("uniqueConstraints", table.uniqueConstraints());
ad.setValue("joinColumns", table.joinColumns());
ad.setValue("inverseJoinColumns", table.inverseJoinColumns());
}
}
if (StringHelper.isEmpty((String) ad.valueOf("schema")) && StringHelper.isNotEmpty(defaults.getSchema())) {
ad.setValue("schema", defaults.getSchema());
}
if (StringHelper.isEmpty((String) ad.valueOf("catalog")) && StringHelper.isNotEmpty(defaults.getCatalog())) {
ad.setValue("catalog", defaults.getCatalog());
}
return AnnotationFactory.create(ad);
} else if (defaults.canUseJavaAnnotations()) {
return getPhysicalAnnotation(annotationType);
} else {
return null;
}
}
use of jakarta.persistence.ManyToMany in project hibernate-orm by hibernate.
the class CollectionBinder method defineFetchingStrategy.
private void defineFetchingStrategy() {
LazyCollection lazy = property.getAnnotation(LazyCollection.class);
Fetch fetch = property.getAnnotation(Fetch.class);
OneToMany oneToMany = property.getAnnotation(OneToMany.class);
ManyToMany manyToMany = property.getAnnotation(ManyToMany.class);
ElementCollection elementCollection = property.getAnnotation(ElementCollection.class);
ManyToAny manyToAny = property.getAnnotation(ManyToAny.class);
FetchType fetchType;
if (oneToMany != null) {
fetchType = oneToMany.fetch();
} else if (manyToMany != null) {
fetchType = manyToMany.fetch();
} else if (elementCollection != null) {
fetchType = elementCollection.fetch();
} else if (manyToAny != null) {
fetchType = FetchType.LAZY;
} else {
throw new AssertionFailure("Define fetch strategy on a property not annotated with @ManyToOne nor @OneToMany nor @ElementCollection");
}
if (lazy != null) {
collection.setLazy(!(lazy.value() == LazyCollectionOption.FALSE));
collection.setExtraLazy(lazy.value() == LazyCollectionOption.EXTRA);
} else {
collection.setLazy(fetchType == FetchType.LAZY);
collection.setExtraLazy(false);
}
if (fetch != null) {
if (fetch.value() == org.hibernate.annotations.FetchMode.JOIN) {
collection.setFetchMode(FetchMode.JOIN);
collection.setLazy(false);
} else if (fetch.value() == org.hibernate.annotations.FetchMode.SELECT) {
collection.setFetchMode(FetchMode.SELECT);
} else if (fetch.value() == org.hibernate.annotations.FetchMode.SUBSELECT) {
collection.setFetchMode(FetchMode.SELECT);
collection.setSubselectLoadable(true);
collection.getOwner().setSubselectLoadableCollections(true);
} else {
throw new AssertionFailure("Unknown FetchMode: " + fetch.value());
}
} else {
collection.setFetchMode(AnnotationBinder.getFetchMode(fetchType));
}
}
use of jakarta.persistence.ManyToMany in project hibernate-orm by hibernate.
the class Ejb3XmlManyToManyTest method testCascadeAllPlusMore.
/**
* Make sure that it doesn't break the handler when {@link CascadeType#ALL}
* is specified in addition to a default cascade-persist or individual
* cascade settings.
*/
@Test
public void testCascadeAllPlusMore() throws Exception {
reader = getReader(Entity2.class, "field1", "many-to-many.orm20.xml");
assertAnnotationPresent(ManyToMany.class);
ManyToMany relAnno = reader.getAnnotation(ManyToMany.class);
assertEquals(6, relAnno.cascade().length);
assertEquals(CascadeType.ALL, relAnno.cascade()[0]);
assertEquals(CascadeType.PERSIST, relAnno.cascade()[1]);
assertEquals(CascadeType.MERGE, relAnno.cascade()[2]);
assertEquals(CascadeType.REMOVE, relAnno.cascade()[3]);
assertEquals(CascadeType.REFRESH, relAnno.cascade()[4]);
assertEquals(CascadeType.DETACH, relAnno.cascade()[5]);
}
Aggregations