Search in sources :

Example 1 with XProperty

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);
    }
}
Also used : XProperty(org.hibernate.annotations.common.reflection.XProperty) Audited(org.hibernate.envers.Audited) NotAudited(org.hibernate.envers.NotAudited) AuditOverride(org.hibernate.envers.AuditOverride) XClass(org.hibernate.annotations.common.reflection.XClass) XClass(org.hibernate.annotations.common.reflection.XClass)

Example 2 with XProperty

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.");
            }
        }
    }
}
Also used : XProperty(org.hibernate.annotations.common.reflection.XProperty) ModifiedEntityNames(org.hibernate.envers.ModifiedEntityNames) PropertyData(org.hibernate.envers.internal.entities.PropertyData) Set(java.util.Set) RevisionTimestamp(org.hibernate.envers.RevisionTimestamp) RevisionNumber(org.hibernate.envers.RevisionNumber) XClass(org.hibernate.annotations.common.reflection.XClass) Date(java.util.Date) MappingException(org.hibernate.MappingException) Column(javax.persistence.Column)

Example 3 with XProperty

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());
    }
}
Also used : GeneratedValue(javax.persistence.GeneratedValue) XProperty(org.hibernate.annotations.common.reflection.XProperty) HashMap(java.util.HashMap) IdentifierGeneratorDefinition(org.hibernate.boot.model.IdentifierGeneratorDefinition) AnnotationException(org.hibernate.AnnotationException) EmbeddedId(javax.persistence.EmbeddedId) XClass(org.hibernate.annotations.common.reflection.XClass) Embeddable(javax.persistence.Embeddable)

Example 4 with XProperty

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);
            }
        }
    }
}
Also used : HashMap(java.util.HashMap) MapKeyJoinColumnDelegator(org.hibernate.cfg.annotations.MapKeyJoinColumnDelegator) Index(org.hibernate.annotations.Index) XClass(org.hibernate.annotations.common.reflection.XClass) ManyToOne(javax.persistence.ManyToOne) DiscriminatorFormula(org.hibernate.annotations.DiscriminatorFormula) Formula(org.hibernate.annotations.Formula) PrimaryKeyJoinColumn(javax.persistence.PrimaryKeyJoinColumn) MapKeyJoinColumn(javax.persistence.MapKeyJoinColumn) JoinColumn(javax.persistence.JoinColumn) AnnotationException(org.hibernate.AnnotationException) ElementCollection(javax.persistence.ElementCollection) NaturalId(org.hibernate.annotations.NaturalId) RootClass(org.hibernate.mapping.RootClass) OrderColumn(javax.persistence.OrderColumn) EmbeddedId(javax.persistence.EmbeddedId) ListIndexBase(org.hibernate.annotations.ListIndexBase) OneToMany(javax.persistence.OneToMany) CollectionId(org.hibernate.annotations.CollectionId) LazyGroup(org.hibernate.annotations.LazyGroup) MapsId(javax.persistence.MapsId) NaturalId(org.hibernate.annotations.NaturalId) EmbeddedId(javax.persistence.EmbeddedId) Id(javax.persistence.Id) CollectionId(org.hibernate.annotations.CollectionId) CollectionBinder(org.hibernate.cfg.annotations.CollectionBinder) OnDelete(org.hibernate.annotations.OnDelete) Cache(org.hibernate.annotations.Cache) NaturalIdCache(org.hibernate.annotations.NaturalIdCache) Basic(javax.persistence.Basic) MapsId(javax.persistence.MapsId) MapKeyJoinColumns(javax.persistence.MapKeyJoinColumns) OneToOne(javax.persistence.OneToOne) MapKeyColumn(javax.persistence.MapKeyColumn) OrderColumn(javax.persistence.OrderColumn) PrimaryKeyJoinColumn(javax.persistence.PrimaryKeyJoinColumn) MapKeyJoinColumn(javax.persistence.MapKeyJoinColumn) Column(javax.persistence.Column) DiscriminatorColumn(javax.persistence.DiscriminatorColumn) JoinColumn(javax.persistence.JoinColumn) PropertyBinder(org.hibernate.cfg.annotations.PropertyBinder) Property(org.hibernate.mapping.Property) XProperty(org.hibernate.annotations.common.reflection.XProperty) Cascade(org.hibernate.annotations.Cascade) XProperty(org.hibernate.annotations.common.reflection.XProperty) MapKeyJoinColumns(javax.persistence.MapKeyJoinColumns) Columns(org.hibernate.annotations.Columns) JoinColumns(javax.persistence.JoinColumns) PrimaryKeyJoinColumns(javax.persistence.PrimaryKeyJoinColumns) Join(org.hibernate.mapping.Join) ManyToMany(javax.persistence.ManyToMany) MapKeyColumnDelegator(org.hibernate.cfg.annotations.MapKeyColumnDelegator) UniqueConstraint(javax.persistence.UniqueConstraint) Constraint(org.hibernate.mapping.Constraint) SimpleValue(org.hibernate.mapping.SimpleValue) MapKeyJoinColumn(javax.persistence.MapKeyJoinColumn) IdentifierGeneratorDefinition(org.hibernate.boot.model.IdentifierGeneratorDefinition) NotFound(org.hibernate.annotations.NotFound) JoinTable(javax.persistence.JoinTable)

Example 5 with XProperty

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);
        }
    }
}
Also used : RootClass(org.hibernate.mapping.RootClass) XProperty(org.hibernate.annotations.common.reflection.XProperty) HashMap(java.util.HashMap) IdGenerator(org.hibernate.mapping.IdGenerator) SimpleValue(org.hibernate.mapping.SimpleValue) SimpleValueBinder(org.hibernate.cfg.annotations.SimpleValueBinder) AnnotationException(org.hibernate.AnnotationException) PropertyBinder(org.hibernate.cfg.annotations.PropertyBinder) Component(org.hibernate.mapping.Component) Property(org.hibernate.mapping.Property) XProperty(org.hibernate.annotations.common.reflection.XProperty) PersistentClass(org.hibernate.mapping.PersistentClass)

Aggregations

XProperty (org.hibernate.annotations.common.reflection.XProperty)20 XClass (org.hibernate.annotations.common.reflection.XClass)9 AnnotationException (org.hibernate.AnnotationException)7 HashMap (java.util.HashMap)6 ManyToOne (javax.persistence.ManyToOne)6 EmbeddedId (javax.persistence.EmbeddedId)5 MappingException (org.hibernate.MappingException)5 Component (org.hibernate.mapping.Component)5 Column (javax.persistence.Column)4 Id (javax.persistence.Id)4 JoinColumn (javax.persistence.JoinColumn)4 Property (org.hibernate.mapping.Property)4 DiscriminatorColumn (javax.persistence.DiscriminatorColumn)3 GeneratedValue (javax.persistence.GeneratedValue)3 JoinColumns (javax.persistence.JoinColumns)3 ManyToMany (javax.persistence.ManyToMany)3 MapsId (javax.persistence.MapsId)3 OneToOne (javax.persistence.OneToOne)3 UniqueConstraint (javax.persistence.UniqueConstraint)3 CollectionId (org.hibernate.annotations.CollectionId)3