use of org.hibernate.annotations.common.reflection.XProperty in project hibernate-orm by hibernate.
the class AuditedPropertiesReader method readAuditOverrides.
/**
* Recursively constructs sets of audited and not audited properties and classes which behavior has been overridden
* using {@link AuditOverride} annotation.
*
* @param clazz Class that is being processed. Currently mapped entity shall be passed during first invocation.
*/
private void readAuditOverrides(XClass clazz) {
/* TODO: Code to remove with @Audited.auditParents - start. */
final Audited allClassAudited = clazz.getAnnotation(Audited.class);
if (allClassAudited != null && allClassAudited.auditParents().length > 0) {
for (Class c : allClassAudited.auditParents()) {
final XClass parentClass = reflectionManager.toXClass(c);
checkSuperclass(clazz, parentClass);
if (!overriddenNotAuditedClasses.contains(parentClass)) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add(parentClass);
}
}
}
/* TODO: Code to remove with @Audited.auditParents - finish. */
final List<AuditOverride> auditOverrides = computeAuditOverrides(clazz);
for (AuditOverride auditOverride : auditOverrides) {
if (auditOverride.forClass() != void.class) {
final XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass());
checkSuperclass(clazz, overrideClass);
final String propertyName = auditOverride.name();
if (!StringTools.isEmpty(propertyName)) {
// Override @Audited annotation on property level.
final XProperty property = getProperty(overrideClass, propertyName);
if (auditOverride.isAudited()) {
if (!overriddenNotAuditedProperties.contains(property)) {
// If the property has not been marked as not audited by the subclass.
overriddenAuditedProperties.add(property);
}
} else {
if (!overriddenAuditedProperties.contains(property)) {
// If the property has not been marked as audited by the subclass.
overriddenNotAuditedProperties.add(property);
}
}
} else {
// Override @Audited annotation on class level.
if (auditOverride.isAudited()) {
if (!overriddenNotAuditedClasses.contains(overrideClass)) {
// If the class has not been marked as not audited by the subclass.
overriddenAuditedClasses.add(overrideClass);
}
} else {
if (!overriddenAuditedClasses.contains(overrideClass)) {
// If the class has not been marked as audited by the subclass.
overriddenNotAuditedClasses.add(overrideClass);
}
}
}
}
}
final XClass superclass = clazz.getSuperclass();
if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) {
readAuditOverrides(superclass);
}
}
use of org.hibernate.annotations.common.reflection.XProperty in project hibernate-orm by hibernate.
the class RevisionInfoConfiguration method searchForRevisionInfoCfgInProperties.
private void searchForRevisionInfoCfgInProperties(XClass clazz, ReflectionManager reflectionManager, MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound, MutableBoolean modifiedEntityNamesFound, String accessType) {
for (XProperty property : clazz.getDeclaredProperties(accessType)) {
final RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class);
final RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class);
final ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class);
if (revisionNumber != null) {
if (revisionNumberFound.isSet()) {
throw new MappingException("Only one property may be annotated with @RevisionNumber!");
}
final XClass revisionNumberClass = property.getType();
if (reflectionManager.equals(revisionNumberClass, Integer.class) || reflectionManager.equals(revisionNumberClass, Integer.TYPE)) {
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null);
revisionNumberFound.set();
} else if (reflectionManager.equals(revisionNumberClass, Long.class) || reflectionManager.equals(revisionNumberClass, Long.TYPE)) {
revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null);
revisionNumberFound.set();
// The default is integer
revisionPropType = "long";
} else {
throw new MappingException("The field annotated with @RevisionNumber must be of type " + "int, Integer, long or Long");
}
// Getting the @Column definition of the revision number property, to later use that info to
// generate the same mapping for the relation from an audit table's revision number to the
// revision entity revision number.
final Column revisionPropColumn = property.getAnnotation(Column.class);
if (revisionPropColumn != null) {
revisionPropSqlType = revisionPropColumn.columnDefinition();
}
}
if (revisionTimestamp != null) {
if (revisionTimestampFound.isSet()) {
throw new MappingException("Only one property may be annotated with @RevisionTimestamp!");
}
final XClass revisionTimestampClass = property.getType();
if (reflectionManager.equals(revisionTimestampClass, Long.class) || reflectionManager.equals(revisionTimestampClass, Long.TYPE) || reflectionManager.equals(revisionTimestampClass, Date.class) || reflectionManager.equals(revisionTimestampClass, java.sql.Date.class)) {
revisionInfoTimestampData = new PropertyData(property.getName(), property.getName(), accessType, null);
revisionTimestampFound.set();
} else {
throw new MappingException("The field annotated with @RevisionTimestamp must be of type " + "long, Long, java.util.Date or java.sql.Date");
}
}
if (modifiedEntityNames != null) {
if (modifiedEntityNamesFound.isSet()) {
throw new MappingException("Only one property may be annotated with @ModifiedEntityNames!");
}
final XClass modifiedEntityNamesClass = property.getType();
if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) && reflectionManager.equals(property.getElementClass(), String.class)) {
modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null);
modifiedEntityNamesFound.set();
} else {
throw new MappingException("The field annotated with @ModifiedEntityNames must be of Set<String> type.");
}
}
}
}
use of org.hibernate.annotations.common.reflection.XProperty in project hibernate-orm by hibernate.
the class AnnotationBinder method processId.
private static void processId(PropertyHolder propertyHolder, PropertyData inferredData, SimpleValue idValue, HashMap<String, IdentifierGeneratorDefinition> classGenerators, boolean isIdentifierMapper, MetadataBuildingContext buildingContext) {
if (isIdentifierMapper) {
throw new AnnotationException("@IdClass class should not have @Id nor @EmbeddedId properties: " + BinderHelper.getPath(propertyHolder, inferredData));
}
XClass returnedClass = inferredData.getClassOrElement();
XProperty property = inferredData.getProperty();
//clone classGenerator and override with local values
HashMap<String, IdentifierGeneratorDefinition> localGenerators = (HashMap<String, IdentifierGeneratorDefinition>) classGenerators.clone();
localGenerators.putAll(buildLocalGenerators(property, buildingContext));
//manage composite related metadata
//guess if its a component and find id data access (property, field etc)
final boolean isComponent = returnedClass.isAnnotationPresent(Embeddable.class) || property.isAnnotationPresent(EmbeddedId.class);
GeneratedValue generatedValue = property.getAnnotation(GeneratedValue.class);
String generatorType = generatedValue != null ? generatorType(generatedValue.strategy(), buildingContext, returnedClass) : "assigned";
String generatorName = generatedValue != null ? generatedValue.generator() : BinderHelper.ANNOTATION_STRING_DEFAULT;
if (isComponent) {
//a component must not have any generator
generatorType = "assigned";
}
BinderHelper.makeIdGenerator(idValue, generatorType, generatorName, buildingContext, localGenerators);
if (LOG.isTraceEnabled()) {
LOG.tracev("Bind {0} on {1}", (isComponent ? "@EmbeddedId" : "@Id"), inferredData.getPropertyName());
}
}
use of org.hibernate.annotations.common.reflection.XProperty in project hibernate-orm by hibernate.
the class AnnotationBinder method processElementAnnotations.
/*
* Process annotation of a particular property
*/
private static void processElementAnnotations(PropertyHolder propertyHolder, Nullability nullability, PropertyData inferredData, HashMap<String, IdentifierGeneratorDefinition> classGenerators, EntityBinder entityBinder, boolean isIdentifierMapper, boolean isComponentEmbedded, boolean inSecondPass, MetadataBuildingContext context, Map<XClass, InheritanceState> inheritanceStatePerClass) throws MappingException {
if (!propertyHolder.isComponent()) {
if (entityBinder.isPropertyDefinedInSuperHierarchy(inferredData.getPropertyName())) {
LOG.debugf("Skipping attribute [%s : %s] as it was already processed as part of super hierarchy", inferredData.getClassOrElementName(), inferredData.getPropertyName());
return;
}
}
/**
* inSecondPass can only be used to apply right away the second pass of a composite-element
* Because it's a value type, there is no bidirectional association, hence second pass
* ordering does not matter
*/
final boolean traceEnabled = LOG.isTraceEnabled();
if (traceEnabled) {
LOG.tracev("Processing annotations of {0}.{1}", propertyHolder.getEntityName(), inferredData.getPropertyName());
}
final XProperty property = inferredData.getProperty();
if (property.isAnnotationPresent(Parent.class)) {
if (propertyHolder.isComponent()) {
propertyHolder.setParentProperty(property.getName());
} else {
throw new AnnotationException("@Parent cannot be applied outside an embeddable object: " + BinderHelper.getPath(propertyHolder, inferredData));
}
return;
}
ColumnsBuilder columnsBuilder = new ColumnsBuilder(propertyHolder, nullability, property, inferredData, entityBinder, context).extractMetadata();
Ejb3Column[] columns = columnsBuilder.getColumns();
Ejb3JoinColumn[] joinColumns = columnsBuilder.getJoinColumns();
final XClass returnedClass = inferredData.getClassOrElement();
//prepare PropertyBinder
PropertyBinder propertyBinder = new PropertyBinder();
propertyBinder.setName(inferredData.getPropertyName());
propertyBinder.setReturnedClassName(inferredData.getTypeName());
propertyBinder.setAccessType(inferredData.getDefaultAccess());
propertyBinder.setHolder(propertyHolder);
propertyBinder.setProperty(property);
propertyBinder.setReturnedClass(inferredData.getPropertyClass());
propertyBinder.setBuildingContext(context);
if (isIdentifierMapper) {
propertyBinder.setInsertable(false);
propertyBinder.setUpdatable(false);
}
propertyBinder.setDeclaringClass(inferredData.getDeclaringClass());
propertyBinder.setEntityBinder(entityBinder);
propertyBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
boolean isId = !entityBinder.isIgnoreIdAnnotations() && (property.isAnnotationPresent(Id.class) || property.isAnnotationPresent(EmbeddedId.class));
propertyBinder.setId(isId);
final LazyGroup lazyGroupAnnotation = property.getAnnotation(LazyGroup.class);
if (lazyGroupAnnotation != null) {
propertyBinder.setLazyGroup(lazyGroupAnnotation.value());
}
if (property.isAnnotationPresent(Version.class)) {
if (isIdentifierMapper) {
throw new AnnotationException("@IdClass class should not have @Version property");
}
if (!(propertyHolder.getPersistentClass() instanceof RootClass)) {
throw new AnnotationException("Unable to define/override @Version on a subclass: " + propertyHolder.getEntityName());
}
if (!propertyHolder.isEntity()) {
throw new AnnotationException("Unable to define @Version on an embedded class: " + propertyHolder.getEntityName());
}
if (traceEnabled) {
LOG.tracev("{0} is a version property", inferredData.getPropertyName());
}
RootClass rootClass = (RootClass) propertyHolder.getPersistentClass();
propertyBinder.setColumns(columns);
Property prop = propertyBinder.makePropertyValueAndBind();
setVersionInformation(property, propertyBinder);
rootClass.setVersion(prop);
//If version is on a mapped superclass, update the mapping
final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(inferredData.getDeclaringClass(), inheritanceStatePerClass, context);
if (superclass != null) {
superclass.setDeclaredVersion(prop);
} else {
//we know the property is on the actual entity
rootClass.setDeclaredVersion(prop);
}
SimpleValue simpleValue = (SimpleValue) prop.getValue();
simpleValue.setNullValue("undefined");
rootClass.setOptimisticLockStyle(OptimisticLockStyle.VERSION);
if (traceEnabled) {
LOG.tracev("Version name: {0}, unsavedValue: {1}", rootClass.getVersion().getName(), ((SimpleValue) rootClass.getVersion().getValue()).getNullValue());
}
} else {
final boolean forcePersist = property.isAnnotationPresent(MapsId.class) || property.isAnnotationPresent(Id.class);
if (property.isAnnotationPresent(ManyToOne.class)) {
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().equals(NotFoundAction.IGNORE);
OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals(onDeleteAnn.action());
JoinTable assocTable = propertyHolder.getJoinTable(property);
if (assocTable != null) {
Join join = propertyHolder.addJoin(assocTable, false);
for (Ejb3JoinColumn joinColumn : joinColumns) {
joinColumn.setExplicitTableName(join.getTable().getName());
}
}
final boolean mandatory = !ann.optional() || forcePersist;
bindManyToOne(getCascadeStrategy(ann.cascade(), hibernateCascade, false, forcePersist), joinColumns, !mandatory, ignoreNotFound, onDeleteCascade, ToOneBinder.getTargetEntity(inferredData, context), propertyHolder, inferredData, false, isIdentifierMapper, inSecondPass, propertyBinder, context);
} else if (property.isAnnotationPresent(OneToOne.class)) {
OneToOne ann = property.getAnnotation(OneToOne.class);
//check validity
if (property.isAnnotationPresent(Column.class) || property.isAnnotationPresent(Columns.class)) {
throw new AnnotationException("@Column(s) not allowed on a @OneToOne property: " + BinderHelper.getPath(propertyHolder, inferredData));
}
//FIXME support a proper PKJCs
boolean trueOneToOne = property.isAnnotationPresent(PrimaryKeyJoinColumn.class) || property.isAnnotationPresent(PrimaryKeyJoinColumns.class);
Cascade hibernateCascade = property.getAnnotation(Cascade.class);
NotFound notFound = property.getAnnotation(NotFound.class);
boolean ignoreNotFound = notFound != null && notFound.action().equals(NotFoundAction.IGNORE);
OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals(onDeleteAnn.action());
JoinTable assocTable = propertyHolder.getJoinTable(property);
if (assocTable != null) {
Join join = propertyHolder.addJoin(assocTable, false);
for (Ejb3JoinColumn joinColumn : joinColumns) {
joinColumn.setExplicitTableName(join.getTable().getName());
}
}
//MapsId means the columns belong to the pk => not null
//@OneToOne with @PKJC can still be optional
final boolean mandatory = !ann.optional() || forcePersist;
bindOneToOne(getCascadeStrategy(ann.cascade(), hibernateCascade, ann.orphanRemoval(), forcePersist), joinColumns, !mandatory, getFetchMode(ann.fetch()), ignoreNotFound, onDeleteCascade, ToOneBinder.getTargetEntity(inferredData, context), propertyHolder, inferredData, ann.mappedBy(), trueOneToOne, isIdentifierMapper, inSecondPass, propertyBinder, context);
} else if (property.isAnnotationPresent(org.hibernate.annotations.Any.class)) {
//check validity
if (property.isAnnotationPresent(Column.class) || property.isAnnotationPresent(Columns.class)) {
throw new AnnotationException("@Column(s) not allowed on a @Any property: " + BinderHelper.getPath(propertyHolder, inferredData));
}
Cascade hibernateCascade = property.getAnnotation(Cascade.class);
OnDelete onDeleteAnn = property.getAnnotation(OnDelete.class);
boolean onDeleteCascade = onDeleteAnn != null && OnDeleteAction.CASCADE.equals(onDeleteAnn.action());
JoinTable assocTable = propertyHolder.getJoinTable(property);
if (assocTable != null) {
Join join = propertyHolder.addJoin(assocTable, false);
for (Ejb3JoinColumn joinColumn : joinColumns) {
joinColumn.setExplicitTableName(join.getTable().getName());
}
}
bindAny(getCascadeStrategy(null, hibernateCascade, false, forcePersist), //@Any has not cascade attribute
joinColumns, onDeleteCascade, nullability, propertyHolder, inferredData, entityBinder, isIdentifierMapper, context);
} else if (property.isAnnotationPresent(OneToMany.class) || property.isAnnotationPresent(ManyToMany.class) || property.isAnnotationPresent(ElementCollection.class) || property.isAnnotationPresent(ManyToAny.class)) {
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));
}
final IndexColumn indexColumn;
if (property.isAnnotationPresent(OrderColumn.class)) {
indexColumn = IndexColumn.buildColumnFromAnnotation(property.getAnnotation(OrderColumn.class), propertyHolder, inferredData, entityBinder.getSecondaryTables(), context);
if (property.isAnnotationPresent(ListIndexBase.class)) {
indexColumn.setBase((property.getAnnotation(ListIndexBase.class)).value());
}
} else {
//if @IndexColumn is not there, the generated IndexColumn is an implicit column and not used.
//so we can leave the legacy processing as the default
indexColumn = IndexColumn.buildColumnFromAnnotation(property.getAnnotation(org.hibernate.annotations.IndexColumn.class), propertyHolder, inferredData, context);
}
CollectionBinder collectionBinder = CollectionBinder.getCollectionBinder(propertyHolder.getEntityName(), property, !indexColumn.isImplicit(), property.isAnnotationPresent(MapKeyType.class), context);
collectionBinder.setIndexColumn(indexColumn);
collectionBinder.setMapKey(property.getAnnotation(MapKey.class));
collectionBinder.setPropertyName(inferredData.getPropertyName());
collectionBinder.setBatchSize(property.getAnnotation(BatchSize.class));
collectionBinder.setJpaOrderBy(property.getAnnotation(javax.persistence.OrderBy.class));
collectionBinder.setSqlOrderBy(property.getAnnotation(OrderBy.class));
collectionBinder.setSort(property.getAnnotation(Sort.class));
collectionBinder.setNaturalSort(property.getAnnotation(SortNatural.class));
collectionBinder.setComparatorSort(property.getAnnotation(SortComparator.class));
Cache cachAnn = property.getAnnotation(Cache.class);
collectionBinder.setCache(cachAnn);
collectionBinder.setPropertyHolder(propertyHolder);
Cascade hibernateCascade = property.getAnnotation(Cascade.class);
NotFound notFound = property.getAnnotation(NotFound.class);
boolean ignoreNotFound = notFound != null && notFound.action().equals(NotFoundAction.IGNORE);
collectionBinder.setIgnoreNotFound(ignoreNotFound);
collectionBinder.setCollectionType(inferredData.getProperty().getElementClass());
collectionBinder.setBuildingContext(context);
collectionBinder.setAccessType(inferredData.getDefaultAccess());
Ejb3Column[] elementColumns;
//do not use "element" if you are a JPA 2 @ElementCollection only for legacy Hibernate mappings
boolean isJPA2ForValueMapping = property.isAnnotationPresent(ElementCollection.class);
PropertyData virtualProperty = isJPA2ForValueMapping ? inferredData : new WrappedInferredData(inferredData, "element");
if (property.isAnnotationPresent(Column.class) || property.isAnnotationPresent(Formula.class)) {
Column ann = property.getAnnotation(Column.class);
Formula formulaAnn = property.getAnnotation(Formula.class);
elementColumns = Ejb3Column.buildColumnFromAnnotation(new Column[] { ann }, formulaAnn, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
} else if (property.isAnnotationPresent(Columns.class)) {
Columns anns = property.getAnnotation(Columns.class);
elementColumns = Ejb3Column.buildColumnFromAnnotation(anns.columns(), null, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
} else {
elementColumns = Ejb3Column.buildColumnFromAnnotation(null, null, nullability, propertyHolder, virtualProperty, entityBinder.getSecondaryTables(), context);
}
{
Column[] keyColumns = null;
//JPA 2 has priority and has different default column values, differenciate legacy from JPA 2
Boolean isJPA2 = null;
if (property.isAnnotationPresent(MapKeyColumn.class)) {
isJPA2 = Boolean.TRUE;
keyColumns = new Column[] { new MapKeyColumnDelegator(property.getAnnotation(MapKeyColumn.class)) };
}
//not explicitly legacy
if (isJPA2 == null) {
isJPA2 = Boolean.TRUE;
}
//nullify empty array
keyColumns = keyColumns != null && keyColumns.length > 0 ? keyColumns : null;
//"mapkey" is the legacy column name of the key column pre JPA 2
PropertyData mapKeyVirtualProperty = new WrappedInferredData(inferredData, "mapkey");
Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation(keyColumns, null, Nullability.FORCED_NOT_NULL, propertyHolder, isJPA2 ? inferredData : mapKeyVirtualProperty, isJPA2 ? "_KEY" : null, entityBinder.getSecondaryTables(), context);
collectionBinder.setMapKeyColumns(mapColumns);
}
{
JoinColumn[] joinKeyColumns = null;
//JPA 2 has priority and has different default column values, differenciate legacy from JPA 2
Boolean isJPA2 = null;
if (property.isAnnotationPresent(MapKeyJoinColumns.class)) {
isJPA2 = Boolean.TRUE;
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)) {
isJPA2 = Boolean.TRUE;
joinKeyColumns = new JoinColumn[] { new MapKeyJoinColumnDelegator(property.getAnnotation(MapKeyJoinColumn.class)) };
}
//not explicitly legacy
if (isJPA2 == null) {
isJPA2 = Boolean.TRUE;
}
PropertyData mapKeyVirtualProperty = new WrappedInferredData(inferredData, "mapkey");
Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumnsWithDefaultColumnSuffix(joinKeyColumns, null, entityBinder.getSecondaryTables(), propertyHolder, isJPA2 ? inferredData.getPropertyName() : mapKeyVirtualProperty.getPropertyName(), isJPA2 ? "_KEY" : null, 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;
if (oneToManyAnn != null) {
for (Ejb3JoinColumn column : joinColumns) {
if (column.isSecondary()) {
throw new NotYetImplementedException("Collections having FK in secondary table");
}
}
collectionBinder.setFkJoinColumns(joinColumns);
mappedBy = oneToManyAnn.mappedBy();
collectionBinder.setTargetEntity(context.getBuildingOptions().getReflectionManager().toXClass(oneToManyAnn.targetEntity()));
collectionBinder.setCascadeStrategy(getCascadeStrategy(oneToManyAnn.cascade(), hibernateCascade, oneToManyAnn.orphanRemoval(), false));
collectionBinder.setOneToMany(true);
} else if (elementCollectionAnn != null) {
for (Ejb3JoinColumn 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(context.getBuildingOptions().getReflectionManager().toXClass(targetElement));
//collectionBinder.setCascadeStrategy( getCascadeStrategy( embeddedCollectionAnn.cascade(), hibernateCascade ) );
collectionBinder.setOneToMany(true);
} else if (manyToManyAnn != null) {
mappedBy = manyToManyAnn.mappedBy();
collectionBinder.setTargetEntity(context.getBuildingOptions().getReflectionManager().toXClass(manyToManyAnn.targetEntity()));
collectionBinder.setCascadeStrategy(getCascadeStrategy(manyToManyAnn.cascade(), hibernateCascade, false, false));
collectionBinder.setOneToMany(false);
} else if (property.isAnnotationPresent(ManyToAny.class)) {
mappedBy = "";
collectionBinder.setTargetEntity(context.getBuildingOptions().getReflectionManager().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.equals(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 = (HashMap<String, IdentifierGeneratorDefinition>) classGenerators.clone();
localGenerators.putAll(buildLocalGenerators(property, context));
collectionBinder.setLocalGenerators(localGenerators);
}
collectionBinder.setInheritanceStatePerClass(inheritanceStatePerClass);
collectionBinder.setDeclaringClass(inferredData.getDeclaringClass());
collectionBinder.bind();
} else //Either a regular property or a basic @Id or @EmbeddedId while not ignoring id annotations
if (!isId || !entityBinder.isIgnoreIdAnnotations()) {
//define whether the type is a component or not
boolean isComponent = false;
//Overrides from @MapsId if needed
boolean isOverridden = false;
if (isId || propertyHolder.isOrWithinEmbeddedId() || propertyHolder.isInIdClass()) {
//the associated entity could be using an @IdClass making the overridden property a component
final PropertyData overridingProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(isId, propertyHolder, property.getName(), context);
if (overridingProperty != null) {
isOverridden = true;
final InheritanceState state = inheritanceStatePerClass.get(overridingProperty.getClassOrElement());
if (state != null) {
isComponent = isComponent || state.hasIdClassOrEmbeddedId();
}
//Get the new column
columns = columnsBuilder.overrideColumnFromMapperOrMapsIdProperty(isId);
}
}
isComponent = isComponent || property.isAnnotationPresent(Embedded.class) || property.isAnnotationPresent(EmbeddedId.class) || returnedClass.isAnnotationPresent(Embeddable.class);
if (isComponent) {
String referencedEntityName = null;
if (isOverridden) {
final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(isId, propertyHolder, property.getName(), context);
referencedEntityName = mapsIdProperty.getClassOrElementName();
}
AccessType propertyAccessor = entityBinder.getPropertyAccessor(property);
propertyBinder = bindComponent(inferredData, propertyHolder, propertyAccessor, entityBinder, isIdentifierMapper, context, isComponentEmbedded, isId, inheritanceStatePerClass, referencedEntityName, isOverridden ? (Ejb3JoinColumn[]) columns : null);
} else {
//provide the basic property mapping
boolean optional = true;
boolean lazy = false;
if (property.isAnnotationPresent(Basic.class)) {
Basic ann = property.getAnnotation(Basic.class);
optional = ann.optional();
lazy = ann.fetch() == FetchType.LAZY;
}
//implicit type will check basic types and Serializable classes
if (isId || (!optional && nullability != Nullability.FORCED_NULL)) {
//force columns to not null
for (Ejb3Column col : columns) {
if (isId && col.isFormula()) {
throw new CannotForceNonNullableException(String.format(Locale.ROOT, "Identifier property [%s] cannot contain formula mapping [%s]", HCANNHelper.annotatedElementSignature(property), col.getFormulaString()));
}
col.forceNotNull();
}
}
propertyBinder.setLazy(lazy);
propertyBinder.setColumns(columns);
if (isOverridden) {
final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(isId, propertyHolder, property.getName(), context);
propertyBinder.setReferencedEntityName(mapsIdProperty.getClassOrElementName());
}
propertyBinder.makePropertyValueAndBind();
}
if (isOverridden) {
final PropertyData mapsIdProperty = BinderHelper.getPropertyOverriddenByMapperOrMapsId(isId, propertyHolder, property.getName(), context);
Map<String, IdentifierGeneratorDefinition> localGenerators = (HashMap<String, IdentifierGeneratorDefinition>) classGenerators.clone();
final IdentifierGeneratorDefinition.Builder foreignGeneratorBuilder = new IdentifierGeneratorDefinition.Builder();
foreignGeneratorBuilder.setName("Hibernate-local--foreign generator");
foreignGeneratorBuilder.setStrategy("foreign");
foreignGeneratorBuilder.addParam("property", mapsIdProperty.getPropertyName());
final IdentifierGeneratorDefinition foreignGenerator = foreignGeneratorBuilder.build();
localGenerators.put(foreignGenerator.getName(), foreignGenerator);
BinderHelper.makeIdGenerator((SimpleValue) propertyBinder.getValue(), foreignGenerator.getStrategy(), foreignGenerator.getName(), context, localGenerators);
}
if (isId) {
//components and regular basic types create SimpleValue objects
final SimpleValue value = (SimpleValue) propertyBinder.getValue();
if (!isOverridden) {
processId(propertyHolder, inferredData, value, classGenerators, isIdentifierMapper, context);
}
}
}
}
//init index
//process indexes afterQuery everything: in second pass, many to one has to be done beforeQuery indexes
Index index = property.getAnnotation(Index.class);
if (index != null) {
if (joinColumns != null) {
for (Ejb3Column column : joinColumns) {
column.addIndex(index, inSecondPass);
}
} else {
if (columns != null) {
for (Ejb3Column column : columns) {
column.addIndex(index, inSecondPass);
}
}
}
}
// Natural ID columns must reside in one single UniqueKey within the Table.
// For now, simply ensure consistent naming.
// TODO: AFAIK, there really isn't a reason for these UKs to be created
// on the secondPass. This whole area should go away...
NaturalId naturalIdAnn = property.getAnnotation(NaturalId.class);
if (naturalIdAnn != null) {
if (joinColumns != null) {
for (Ejb3Column column : joinColumns) {
String keyName = "UK_" + Constraint.hashedName(column.getTable().getName() + "_NaturalID");
column.addUniqueKey(keyName, inSecondPass);
}
} else {
for (Ejb3Column column : columns) {
String keyName = "UK_" + Constraint.hashedName(column.getTable().getName() + "_NaturalID");
column.addUniqueKey(keyName, inSecondPass);
}
}
}
}
use of org.hibernate.annotations.common.reflection.XProperty in project hibernate-orm by hibernate.
the class AnnotationBinder method bindIdClass.
private static void bindIdClass(String generatorType, String generatorName, PropertyData inferredData, PropertyData baseInferredData, Ejb3Column[] columns, PropertyHolder propertyHolder, boolean isComposite, AccessType propertyAccessor, EntityBinder entityBinder, boolean isEmbedded, boolean isIdentifierMapper, MetadataBuildingContext buildingContext, Map<XClass, InheritanceState> inheritanceStatePerClass) {
/*
* Fill simple value and property since and Id is a property
*/
PersistentClass persistentClass = propertyHolder.getPersistentClass();
if (!(persistentClass instanceof RootClass)) {
throw new AnnotationException("Unable to define/override @Id(s) on a subclass: " + propertyHolder.getEntityName());
}
RootClass rootClass = (RootClass) persistentClass;
String persistentClassName = rootClass.getClassName();
SimpleValue id;
final String propertyName = inferredData.getPropertyName();
HashMap<String, IdGenerator> localGenerators = new HashMap<String, IdGenerator>();
if (isComposite) {
id = fillComponent(propertyHolder, inferredData, baseInferredData, propertyAccessor, false, entityBinder, isEmbedded, isIdentifierMapper, false, buildingContext, inheritanceStatePerClass);
Component componentId = (Component) id;
componentId.setKey(true);
if (rootClass.getIdentifier() != null) {
throw new AnnotationException(componentId.getComponentClassName() + " must not have @Id properties when used as an @EmbeddedId");
}
if (componentId.getPropertySpan() == 0) {
throw new AnnotationException(componentId.getComponentClassName() + " has no persistent id property");
}
//tuplizers
XProperty property = inferredData.getProperty();
setupComponentTuplizer(property, componentId);
} else {
for (Ejb3Column column : columns) {
//this is an id
column.forceNotNull();
}
SimpleValueBinder value = new SimpleValueBinder();
value.setPropertyName(propertyName);
value.setReturnedClassName(inferredData.getTypeName());
value.setColumns(columns);
value.setPersistentClassName(persistentClassName);
value.setBuildingContext(buildingContext);
value.setType(inferredData.getProperty(), inferredData.getClassOrElement(), persistentClassName, null);
value.setAccessType(propertyAccessor);
id = value.make();
}
rootClass.setIdentifier(id);
BinderHelper.makeIdGenerator(id, generatorType, generatorName, buildingContext, Collections.<String, IdentifierGeneratorDefinition>emptyMap());
if (isEmbedded) {
rootClass.setEmbeddedIdentifier(inferredData.getPropertyClass() == null);
} else {
PropertyBinder binder = new PropertyBinder();
binder.setName(propertyName);
binder.setValue(id);
binder.setAccessType(inferredData.getDefaultAccess());
binder.setProperty(inferredData.getProperty());
Property prop = binder.makeProperty();
rootClass.setIdentifierProperty(prop);
//if the id property is on a superclass, update the metamodel
final org.hibernate.mapping.MappedSuperclass superclass = BinderHelper.getMappedSuperclassOrNull(inferredData.getDeclaringClass(), inheritanceStatePerClass, buildingContext);
if (superclass != null) {
superclass.setDeclaredIdentifierProperty(prop);
} else {
//we know the property is on the actual entity
rootClass.setDeclaredIdentifierProperty(prop);
}
}
}
Aggregations