Search in sources :

Example 11 with JoinColumn

use of javax.persistence.JoinColumn 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 12 with JoinColumn

use of javax.persistence.JoinColumn in project hibernate-orm by hibernate.

the class AnnotationBinder method bindJoinedTableAssociation.

//TODO move that to collection binder?
private static void bindJoinedTableAssociation(XProperty property, MetadataBuildingContext buildingContext, EntityBinder entityBinder, CollectionBinder collectionBinder, PropertyHolder propertyHolder, PropertyData inferredData, String mappedBy) {
    TableBinder associationTableBinder = new TableBinder();
    JoinColumn[] annJoins;
    JoinColumn[] annInverseJoins;
    JoinTable assocTable = propertyHolder.getJoinTable(property);
    CollectionTable collectionTable = property.getAnnotation(CollectionTable.class);
    if (assocTable != null || collectionTable != null) {
        final String catalog;
        final String schema;
        final String tableName;
        final UniqueConstraint[] uniqueConstraints;
        final JoinColumn[] joins;
        final JoinColumn[] inverseJoins;
        final javax.persistence.Index[] jpaIndexes;
        //JPA 2 has priority
        if (collectionTable != null) {
            catalog = collectionTable.catalog();
            schema = collectionTable.schema();
            tableName = collectionTable.name();
            uniqueConstraints = collectionTable.uniqueConstraints();
            joins = collectionTable.joinColumns();
            inverseJoins = null;
            jpaIndexes = collectionTable.indexes();
        } else {
            catalog = assocTable.catalog();
            schema = assocTable.schema();
            tableName = assocTable.name();
            uniqueConstraints = assocTable.uniqueConstraints();
            joins = assocTable.joinColumns();
            inverseJoins = assocTable.inverseJoinColumns();
            jpaIndexes = assocTable.indexes();
        }
        collectionBinder.setExplicitAssociationTable(true);
        if (jpaIndexes != null && jpaIndexes.length > 0) {
            associationTableBinder.setJpaIndex(jpaIndexes);
        }
        if (!BinderHelper.isEmptyAnnotationValue(schema)) {
            associationTableBinder.setSchema(schema);
        }
        if (!BinderHelper.isEmptyAnnotationValue(catalog)) {
            associationTableBinder.setCatalog(catalog);
        }
        if (!BinderHelper.isEmptyAnnotationValue(tableName)) {
            associationTableBinder.setName(tableName);
        }
        associationTableBinder.setUniqueConstraints(uniqueConstraints);
        associationTableBinder.setJpaIndex(jpaIndexes);
        //set check constaint in the second pass
        annJoins = joins.length == 0 ? null : joins;
        annInverseJoins = inverseJoins == null || inverseJoins.length == 0 ? null : inverseJoins;
    } else {
        annJoins = null;
        annInverseJoins = null;
    }
    Ejb3JoinColumn[] joinColumns = Ejb3JoinColumn.buildJoinTableJoinColumns(annJoins, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappedBy, buildingContext);
    Ejb3JoinColumn[] inverseJoinColumns = Ejb3JoinColumn.buildJoinTableJoinColumns(annInverseJoins, entityBinder.getSecondaryTables(), propertyHolder, inferredData.getPropertyName(), mappedBy, buildingContext);
    associationTableBinder.setBuildingContext(buildingContext);
    collectionBinder.setTableBinder(associationTableBinder);
    collectionBinder.setJoinColumns(joinColumns);
    collectionBinder.setInverseJoinColumns(inverseJoinColumns);
}
Also used : UniqueConstraint(javax.persistence.UniqueConstraint) Index(org.hibernate.annotations.Index) PrimaryKeyJoinColumn(javax.persistence.PrimaryKeyJoinColumn) MapKeyJoinColumn(javax.persistence.MapKeyJoinColumn) JoinColumn(javax.persistence.JoinColumn) CollectionTable(javax.persistence.CollectionTable) TableBinder(org.hibernate.cfg.annotations.TableBinder) JoinTable(javax.persistence.JoinTable)

Example 13 with JoinColumn

use of javax.persistence.JoinColumn in project hibernate-orm by hibernate.

the class AbstractPropertyHolder method buildHierarchyColumnOverride.

private void buildHierarchyColumnOverride(XClass element) {
    XClass current = element;
    Map<String, Column[]> columnOverride = new HashMap<String, Column[]>();
    Map<String, JoinColumn[]> joinColumnOverride = new HashMap<String, JoinColumn[]>();
    Map<String, JoinTable> joinTableOverride = new HashMap<String, JoinTable>();
    Map<String, ForeignKey> foreignKeyOverride = new HashMap<String, ForeignKey>();
    while (current != null && !context.getBuildingOptions().getReflectionManager().toXClass(Object.class).equals(current)) {
        if (current.isAnnotationPresent(Entity.class) || current.isAnnotationPresent(MappedSuperclass.class) || current.isAnnotationPresent(Embeddable.class)) {
            //FIXME is embeddable override?
            Map<String, Column[]> currentOverride = buildColumnOverride(current, getPath());
            Map<String, JoinColumn[]> currentJoinOverride = buildJoinColumnOverride(current, getPath());
            Map<String, JoinTable> currentJoinTableOverride = buildJoinTableOverride(current, getPath());
            Map<String, ForeignKey> currentForeignKeyOverride = buildForeignKeyOverride(current, getPath());
            //subclasses have precedence over superclasses
            currentOverride.putAll(columnOverride);
            //subclasses have precedence over superclasses
            currentJoinOverride.putAll(joinColumnOverride);
            //subclasses have precedence over superclasses
            currentJoinTableOverride.putAll(joinTableOverride);
            //subclasses have precedence over superclasses
            currentForeignKeyOverride.putAll(foreignKeyOverride);
            columnOverride = currentOverride;
            joinColumnOverride = currentJoinOverride;
            joinTableOverride = currentJoinTableOverride;
            foreignKeyOverride = currentForeignKeyOverride;
        }
        current = current.getSuperclass();
    }
    holderColumnOverride = columnOverride.size() > 0 ? columnOverride : null;
    holderJoinColumnOverride = joinColumnOverride.size() > 0 ? joinColumnOverride : null;
    holderJoinTableOverride = joinTableOverride.size() > 0 ? joinTableOverride : null;
    holderForeignKeyOverride = foreignKeyOverride.size() > 0 ? foreignKeyOverride : null;
}
Also used : HashMap(java.util.HashMap) ForeignKey(javax.persistence.ForeignKey) XClass(org.hibernate.annotations.common.reflection.XClass) Embeddable(javax.persistence.Embeddable) JoinColumn(javax.persistence.JoinColumn) JoinColumn(javax.persistence.JoinColumn) Column(javax.persistence.Column) JoinTable(javax.persistence.JoinTable)

Example 14 with JoinColumn

use of javax.persistence.JoinColumn in project hibernate-orm by hibernate.

the class CollectionBinder method bindManyToManySecondPass.

protected void bindManyToManySecondPass(Collection collValue, Map persistentClasses, Ejb3JoinColumn[] joinColumns, Ejb3JoinColumn[] inverseJoinColumns, Ejb3Column[] elementColumns, boolean isEmbedded, XClass collType, boolean ignoreNotFound, boolean unique, boolean cascadeDeleteEnabled, TableBinder associationTableBinder, XProperty property, PropertyHolder parentPropertyHolder, MetadataBuildingContext buildingContext) throws MappingException {
    if (property == null) {
        throw new IllegalArgumentException("null was passed for argument property");
    }
    final PersistentClass collectionEntity = (PersistentClass) persistentClasses.get(collType.getName());
    final String hqlOrderBy = extractHqlOrderBy(jpaOrderBy);
    boolean isCollectionOfEntities = collectionEntity != null;
    ManyToAny anyAnn = property.getAnnotation(ManyToAny.class);
    if (LOG.isDebugEnabled()) {
        String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
        if (isCollectionOfEntities && unique) {
            LOG.debugf("Binding a OneToMany: %s through an association table", path);
        } else if (isCollectionOfEntities) {
            LOG.debugf("Binding as ManyToMany: %s", path);
        } else if (anyAnn != null) {
            LOG.debugf("Binding a ManyToAny: %s", path);
        } else {
            LOG.debugf("Binding a collection of element: %s", path);
        }
    }
    //check for user error
    if (!isCollectionOfEntities) {
        if (property.isAnnotationPresent(ManyToMany.class) || property.isAnnotationPresent(OneToMany.class)) {
            String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
            throw new AnnotationException("Use of @OneToMany or @ManyToMany targeting an unmapped class: " + path + "[" + collType + "]");
        } else if (anyAnn != null) {
            if (parentPropertyHolder.getJoinTable(property) == null) {
                String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
                throw new AnnotationException("@JoinTable is mandatory when @ManyToAny is used: " + path);
            }
        } else {
            JoinTable joinTableAnn = parentPropertyHolder.getJoinTable(property);
            if (joinTableAnn != null && joinTableAnn.inverseJoinColumns().length > 0) {
                String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
                throw new AnnotationException("Use of @JoinTable.inverseJoinColumns targeting an unmapped class: " + path + "[" + collType + "]");
            }
        }
    }
    boolean mappedBy = !BinderHelper.isEmptyAnnotationValue(joinColumns[0].getMappedBy());
    if (mappedBy) {
        if (!isCollectionOfEntities) {
            StringBuilder error = new StringBuilder(80).append("Collection of elements must not have mappedBy or association reference an unmapped entity: ").append(collValue.getOwnerEntityName()).append(".").append(joinColumns[0].getPropertyName());
            throw new AnnotationException(error.toString());
        }
        Property otherSideProperty;
        try {
            otherSideProperty = collectionEntity.getRecursiveProperty(joinColumns[0].getMappedBy());
        } catch (MappingException e) {
            throw new AnnotationException("mappedBy reference an unknown target entity property: " + collType + "." + joinColumns[0].getMappedBy() + " in " + collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName());
        }
        Table table;
        if (otherSideProperty.getValue() instanceof Collection) {
            //this is a collection on the other side
            table = ((Collection) otherSideProperty.getValue()).getCollectionTable();
        } else {
            //This is a ToOne with a @JoinTable or a regular property
            table = otherSideProperty.getValue().getTable();
        }
        collValue.setCollectionTable(table);
        String entityName = collectionEntity.getEntityName();
        for (Ejb3JoinColumn column : joinColumns) {
            //column.setDefaultColumnHeader( joinColumns[0].getMappedBy() ); //seems not to be used, make sense
            column.setManyToManyOwnerSideEntityName(entityName);
        }
    } else {
        //FIXME NamingStrategy
        for (Ejb3JoinColumn column : joinColumns) {
            String mappedByProperty = buildingContext.getMetadataCollector().getFromMappedBy(collValue.getOwnerEntityName(), column.getPropertyName());
            Table ownerTable = collValue.getOwner().getTable();
            column.setMappedBy(collValue.getOwner().getEntityName(), collValue.getOwner().getJpaEntityName(), buildingContext.getMetadataCollector().getLogicalTableName(ownerTable), mappedByProperty);
        //				String header = ( mappedByProperty == null ) ? mappings.getLogicalTableName( ownerTable ) : mappedByProperty;
        //				column.setDefaultColumnHeader( header );
        }
        if (StringHelper.isEmpty(associationTableBinder.getName())) {
            //default value
            associationTableBinder.setDefaultName(collValue.getOwner().getClassName(), collValue.getOwner().getEntityName(), collValue.getOwner().getJpaEntityName(), buildingContext.getMetadataCollector().getLogicalTableName(collValue.getOwner().getTable()), collectionEntity != null ? collectionEntity.getClassName() : null, collectionEntity != null ? collectionEntity.getEntityName() : null, collectionEntity != null ? collectionEntity.getJpaEntityName() : null, collectionEntity != null ? buildingContext.getMetadataCollector().getLogicalTableName(collectionEntity.getTable()) : null, joinColumns[0].getPropertyName());
        }
        associationTableBinder.setJPA2ElementCollection(!isCollectionOfEntities && property.isAnnotationPresent(ElementCollection.class));
        collValue.setCollectionTable(associationTableBinder.bind());
    }
    bindFilters(isCollectionOfEntities);
    bindCollectionSecondPass(collValue, collectionEntity, joinColumns, cascadeDeleteEnabled, property, propertyHolder, buildingContext);
    ManyToOne element = null;
    if (isCollectionOfEntities) {
        element = new ManyToOne(buildingContext.getMetadataCollector(), collValue.getCollectionTable());
        collValue.setElement(element);
        element.setReferencedEntityName(collType.getName());
        //element.setFetchMode( fetchMode );
        //element.setLazy( fetchMode != FetchMode.JOIN );
        //make the second join non lazy
        element.setFetchMode(FetchMode.JOIN);
        element.setLazy(false);
        element.setIgnoreNotFound(ignoreNotFound);
        // as per 11.1.38 of JPA 2.0 spec, default to primary key if no column is specified by @OrderBy.
        if (hqlOrderBy != null) {
            collValue.setManyToManyOrdering(buildOrderByClauseFromHql(hqlOrderBy, collectionEntity, collValue.getRole()));
        }
        final ForeignKey fk = property.getAnnotation(ForeignKey.class);
        if (fk != null && !BinderHelper.isEmptyAnnotationValue(fk.name())) {
            element.setForeignKeyName(fk.name());
        } else {
            final JoinTable joinTableAnn = property.getAnnotation(JoinTable.class);
            if (joinTableAnn != null) {
                String foreignKeyName = joinTableAnn.inverseForeignKey().name();
                String foreignKeyDefinition = joinTableAnn.inverseForeignKey().foreignKeyDefinition();
                ConstraintMode foreignKeyValue = joinTableAnn.inverseForeignKey().value();
                if (joinTableAnn.inverseJoinColumns().length != 0) {
                    final JoinColumn joinColumnAnn = joinTableAnn.inverseJoinColumns()[0];
                    if ("".equals(foreignKeyName)) {
                        foreignKeyName = joinColumnAnn.foreignKey().name();
                        foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition();
                    }
                    if (foreignKeyValue != ConstraintMode.NO_CONSTRAINT) {
                        foreignKeyValue = joinColumnAnn.foreignKey().value();
                    }
                }
                if (joinTableAnn.inverseForeignKey().value() == ConstraintMode.NO_CONSTRAINT) {
                    element.setForeignKeyName("none");
                } else {
                    element.setForeignKeyName(StringHelper.nullIfEmpty(foreignKeyName));
                    element.setForeignKeyDefinition(StringHelper.nullIfEmpty(foreignKeyDefinition));
                }
            }
        }
    } else if (anyAnn != null) {
        //@ManyToAny
        //Make sure that collTyp is never used during the @ManyToAny branch: it will be set to void.class
        PropertyData inferredData = new PropertyInferredData(null, property, "unsupported", buildingContext.getBuildingOptions().getReflectionManager());
        //override the table
        for (Ejb3Column column : inverseJoinColumns) {
            column.setTable(collValue.getCollectionTable());
        }
        Any any = BinderHelper.buildAnyValue(anyAnn.metaDef(), inverseJoinColumns, anyAnn.metaColumn(), inferredData, cascadeDeleteEnabled, Nullability.NO_CONSTRAINT, propertyHolder, new EntityBinder(), true, buildingContext);
        collValue.setElement(any);
    } else {
        XClass elementClass;
        AnnotatedClassType classType;
        CollectionPropertyHolder holder = null;
        if (BinderHelper.PRIMITIVE_NAMES.contains(collType.getName())) {
            classType = AnnotatedClassType.NONE;
            elementClass = null;
            holder = PropertyHolderBuilder.buildPropertyHolder(collValue, collValue.getRole(), null, property, parentPropertyHolder, buildingContext);
        } else {
            elementClass = collType;
            classType = buildingContext.getMetadataCollector().getClassType(elementClass);
            holder = PropertyHolderBuilder.buildPropertyHolder(collValue, collValue.getRole(), elementClass, property, parentPropertyHolder, buildingContext);
            // 'parentPropertyHolder' is the PropertyHolder for the owner of the collection
            // 'holder' is the CollectionPropertyHolder.
            // 'property' is the collection XProperty
            parentPropertyHolder.startingProperty(property);
            //force in case of attribute override
            boolean attributeOverride = property.isAnnotationPresent(AttributeOverride.class) || property.isAnnotationPresent(AttributeOverrides.class);
            // todo : force in the case of Convert annotation(s) with embedded paths (beyond key/value prefixes)?
            if (isEmbedded || attributeOverride) {
                classType = AnnotatedClassType.EMBEDDABLE;
            }
        }
        if (AnnotatedClassType.EMBEDDABLE.equals(classType)) {
            holder.prepare(property);
            EntityBinder entityBinder = new EntityBinder();
            PersistentClass owner = collValue.getOwner();
            boolean isPropertyAnnotated;
            //String accessType = access != null ? access.value() : null;
            if (owner.getIdentifierProperty() != null) {
                isPropertyAnnotated = owner.getIdentifierProperty().getPropertyAccessorName().equals("property");
            } else if (owner.getIdentifierMapper() != null && owner.getIdentifierMapper().getPropertySpan() > 0) {
                Property prop = (Property) owner.getIdentifierMapper().getPropertyIterator().next();
                isPropertyAnnotated = prop.getPropertyAccessorName().equals("property");
            } else {
                throw new AssertionFailure("Unable to guess collection property accessor name");
            }
            PropertyData inferredData;
            if (isMap()) {
                //"value" is the JPA 2 prefix for map values (used to be "element")
                if (isHibernateExtensionMapping()) {
                    inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "element", elementClass);
                } else {
                    inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "value", elementClass);
                }
            } else {
                if (isHibernateExtensionMapping()) {
                    inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "element", elementClass);
                } else {
                    //"collection&&element" is not a valid property name => placeholder
                    inferredData = new PropertyPreloadedData(AccessType.PROPERTY, "collection&&element", elementClass);
                }
            }
            //TODO be smart with isNullable
            boolean isNullable = true;
            Component component = AnnotationBinder.fillComponent(holder, inferredData, isPropertyAnnotated ? AccessType.PROPERTY : AccessType.FIELD, isNullable, entityBinder, false, false, true, buildingContext, inheritanceStatePerClass);
            collValue.setElement(component);
            if (StringHelper.isNotEmpty(hqlOrderBy)) {
                String path = collValue.getOwnerEntityName() + "." + joinColumns[0].getPropertyName();
                String orderBy = adjustUserSuppliedValueCollectionOrderingFragment(hqlOrderBy);
                if (orderBy != null) {
                    collValue.setOrderBy(orderBy);
                }
            }
        } else {
            holder.prepare(property);
            SimpleValueBinder elementBinder = new SimpleValueBinder();
            elementBinder.setBuildingContext(buildingContext);
            elementBinder.setReturnedClassName(collType.getName());
            if (elementColumns == null || elementColumns.length == 0) {
                elementColumns = new Ejb3Column[1];
                Ejb3Column column = new Ejb3Column();
                column.setImplicit(false);
                //not following the spec but more clean
                column.setNullable(true);
                column.setLength(Ejb3Column.DEFAULT_COLUMN_LENGTH);
                column.setLogicalColumnName(Collection.DEFAULT_ELEMENT_COLUMN_NAME);
                //TODO create an EMPTY_JOINS collection
                column.setJoins(new HashMap<String, Join>());
                column.setBuildingContext(buildingContext);
                column.bind();
                elementColumns[0] = column;
            }
            //override the table
            for (Ejb3Column column : elementColumns) {
                column.setTable(collValue.getCollectionTable());
            }
            elementBinder.setColumns(elementColumns);
            elementBinder.setType(property, elementClass, collValue.getOwnerEntityName(), holder.resolveElementAttributeConverterDescriptor(property, elementClass));
            elementBinder.setPersistentClassName(propertyHolder.getEntityName());
            elementBinder.setAccessType(accessType);
            collValue.setElement(elementBinder.make());
            String orderBy = adjustUserSuppliedValueCollectionOrderingFragment(hqlOrderBy);
            if (orderBy != null) {
                collValue.setOrderBy(orderBy);
            }
        }
    }
    checkFilterConditions(collValue);
    //FIXME: do optional = false
    if (isCollectionOfEntities) {
        bindManytoManyInverseFk(collectionEntity, inverseJoinColumns, element, unique, buildingContext);
    }
}
Also used : PropertyData(org.hibernate.cfg.PropertyData) HashMap(java.util.HashMap) PropertyInferredData(org.hibernate.cfg.PropertyInferredData) PropertyPreloadedData(org.hibernate.cfg.PropertyPreloadedData) Any(org.hibernate.mapping.Any) ManyToAny(org.hibernate.annotations.ManyToAny) XClass(org.hibernate.annotations.common.reflection.XClass) ManyToOne(org.hibernate.mapping.ManyToOne) MappingException(org.hibernate.MappingException) ManyToAny(org.hibernate.annotations.ManyToAny) JoinColumn(javax.persistence.JoinColumn) Ejb3JoinColumn(org.hibernate.cfg.Ejb3JoinColumn) AnnotationException(org.hibernate.AnnotationException) Ejb3Column(org.hibernate.cfg.Ejb3Column) Component(org.hibernate.mapping.Component) Property(org.hibernate.mapping.Property) XProperty(org.hibernate.annotations.common.reflection.XProperty) PersistentClass(org.hibernate.mapping.PersistentClass) JoinTable(javax.persistence.JoinTable) CollectionTable(javax.persistence.CollectionTable) WhereJoinTable(org.hibernate.annotations.WhereJoinTable) Table(org.hibernate.mapping.Table) FilterJoinTable(org.hibernate.annotations.FilterJoinTable) CollectionPropertyHolder(org.hibernate.cfg.CollectionPropertyHolder) AssertionFailure(org.hibernate.annotations.common.AssertionFailure) ManyToMany(javax.persistence.ManyToMany) ConstraintMode(javax.persistence.ConstraintMode) OneToMany(javax.persistence.OneToMany) ForeignKey(org.hibernate.annotations.ForeignKey) LazyCollection(org.hibernate.annotations.LazyCollection) Collection(org.hibernate.mapping.Collection) ElementCollection(javax.persistence.ElementCollection) Ejb3JoinColumn(org.hibernate.cfg.Ejb3JoinColumn) AnnotatedClassType(org.hibernate.cfg.AnnotatedClassType) JoinTable(javax.persistence.JoinTable) WhereJoinTable(org.hibernate.annotations.WhereJoinTable) FilterJoinTable(org.hibernate.annotations.FilterJoinTable)

Example 15 with JoinColumn

use of javax.persistence.JoinColumn in project hibernate-orm by hibernate.

the class CollectionBinder method buildCollectionKey.

private static SimpleValue buildCollectionKey(Collection collValue, Ejb3JoinColumn[] joinColumns, boolean cascadeDeleteEnabled, XProperty property, PropertyHolder propertyHolder, MetadataBuildingContext buildingContext) {
    //binding key reference using column
    KeyValue keyVal;
    //has to do that here because the referencedProperty creation happens in a FKSecondPass for Many to one yuk!
    if (joinColumns.length > 0 && StringHelper.isNotEmpty(joinColumns[0].getMappedBy())) {
        String entityName = joinColumns[0].getManyToManyOwnerSideEntityName() != null ? "inverse__" + joinColumns[0].getManyToManyOwnerSideEntityName() : joinColumns[0].getPropertyHolder().getEntityName();
        String propRef = buildingContext.getMetadataCollector().getPropertyReferencedAssociation(entityName, joinColumns[0].getMappedBy());
        if (propRef != null) {
            collValue.setReferencedPropertyName(propRef);
            buildingContext.getMetadataCollector().addPropertyReference(collValue.getOwnerEntityName(), propRef);
        }
    }
    String propRef = collValue.getReferencedPropertyName();
    if (propRef == null) {
        keyVal = collValue.getOwner().getIdentifier();
    } else {
        keyVal = (KeyValue) collValue.getOwner().getReferencedProperty(propRef).getValue();
    }
    DependantValue key = new DependantValue(buildingContext.getMetadataCollector(), collValue.getCollectionTable(), keyVal);
    key.setTypeName(null);
    Ejb3Column.checkPropertyConsistency(joinColumns, collValue.getOwnerEntityName());
    key.setNullable(joinColumns.length == 0 || joinColumns[0].isNullable());
    key.setUpdateable(joinColumns.length == 0 || joinColumns[0].isUpdatable());
    key.setCascadeDeleteEnabled(cascadeDeleteEnabled);
    collValue.setKey(key);
    if (property != null) {
        final ForeignKey fk = property.getAnnotation(ForeignKey.class);
        if (fk != null && !BinderHelper.isEmptyAnnotationValue(fk.name())) {
            key.setForeignKeyName(fk.name());
        } else {
            final CollectionTable collectionTableAnn = property.getAnnotation(CollectionTable.class);
            if (collectionTableAnn != null) {
                if (collectionTableAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT) {
                    key.setForeignKeyName("none");
                } else {
                    key.setForeignKeyName(StringHelper.nullIfEmpty(collectionTableAnn.foreignKey().name()));
                    key.setForeignKeyDefinition(StringHelper.nullIfEmpty(collectionTableAnn.foreignKey().foreignKeyDefinition()));
                }
            } else {
                final JoinTable joinTableAnn = property.getAnnotation(JoinTable.class);
                if (joinTableAnn != null) {
                    String foreignKeyName = joinTableAnn.foreignKey().name();
                    String foreignKeyDefinition = joinTableAnn.foreignKey().foreignKeyDefinition();
                    ConstraintMode foreignKeyValue = joinTableAnn.foreignKey().value();
                    if (joinTableAnn.joinColumns().length != 0) {
                        final JoinColumn joinColumnAnn = joinTableAnn.joinColumns()[0];
                        if ("".equals(foreignKeyName)) {
                            foreignKeyName = joinColumnAnn.foreignKey().name();
                            foreignKeyDefinition = joinColumnAnn.foreignKey().foreignKeyDefinition();
                        }
                        if (foreignKeyValue != ConstraintMode.NO_CONSTRAINT) {
                            foreignKeyValue = joinColumnAnn.foreignKey().value();
                        }
                    }
                    if (foreignKeyValue == ConstraintMode.NO_CONSTRAINT) {
                        key.setForeignKeyName("none");
                    } else {
                        key.setForeignKeyName(StringHelper.nullIfEmpty(foreignKeyName));
                        key.setForeignKeyDefinition(StringHelper.nullIfEmpty(foreignKeyDefinition));
                    }
                } else {
                    final javax.persistence.ForeignKey fkOverride = propertyHolder.getOverriddenForeignKey(StringHelper.qualify(propertyHolder.getPath(), property.getName()));
                    if (fkOverride != null && fkOverride.value() == ConstraintMode.NO_CONSTRAINT) {
                        key.setForeignKeyName("none");
                    } else if (fkOverride != null) {
                        key.setForeignKeyName(StringHelper.nullIfEmpty(fkOverride.name()));
                        key.setForeignKeyDefinition(StringHelper.nullIfEmpty(fkOverride.foreignKeyDefinition()));
                    } else {
                        final JoinColumn joinColumnAnn = property.getAnnotation(JoinColumn.class);
                        if (joinColumnAnn != null) {
                            if (joinColumnAnn.foreignKey().value() == ConstraintMode.NO_CONSTRAINT) {
                                key.setForeignKeyName("none");
                            } else {
                                key.setForeignKeyName(StringHelper.nullIfEmpty(joinColumnAnn.foreignKey().name()));
                                key.setForeignKeyDefinition(StringHelper.nullIfEmpty(joinColumnAnn.foreignKey().foreignKeyDefinition()));
                            }
                        }
                    }
                }
            }
        }
    }
    return key;
}
Also used : KeyValue(org.hibernate.mapping.KeyValue) JoinColumn(javax.persistence.JoinColumn) Ejb3JoinColumn(org.hibernate.cfg.Ejb3JoinColumn) CollectionTable(javax.persistence.CollectionTable) DependantValue(org.hibernate.mapping.DependantValue) ConstraintMode(javax.persistence.ConstraintMode) ForeignKey(org.hibernate.annotations.ForeignKey) JoinTable(javax.persistence.JoinTable) WhereJoinTable(org.hibernate.annotations.WhereJoinTable) FilterJoinTable(org.hibernate.annotations.FilterJoinTable)

Aggregations

JoinColumn (javax.persistence.JoinColumn)44 JoinTable (javax.persistence.JoinTable)17 Field (java.lang.reflect.Field)15 Method (java.lang.reflect.Method)14 ManyToOne (javax.persistence.ManyToOne)14 ReflectUtil (org.eweb4j.util.ReflectUtil)14 MapKeyJoinColumn (javax.persistence.MapKeyJoinColumn)13 PrimaryKeyJoinColumn (javax.persistence.PrimaryKeyJoinColumn)13 Test (org.junit.Test)12 JoinColumns (javax.persistence.JoinColumns)11 OneToOne (javax.persistence.OneToOne)10 UniqueConstraint (javax.persistence.UniqueConstraint)9 Column (javax.persistence.Column)8 ManyToMany (javax.persistence.ManyToMany)8 OneToMany (javax.persistence.OneToMany)6 DAOException (org.eweb4j.orm.dao.DAOException)6 Id (javax.persistence.Id)5 MapKeyJoinColumns (javax.persistence.MapKeyJoinColumns)5 HashMap (java.util.HashMap)4 CollectionTable (javax.persistence.CollectionTable)4