private FilterSource[] determineFilterSources(PluralAssociationAttribute associationAttribute) {
   AnnotationInstance filtersAnnotation =
       JandexHelper.getSingleAnnotation(
           associationAttribute.annotations(), HibernateDotNames.FILTERS);
   List<FilterSource> filterSourceList = new ArrayList<FilterSource>();
   if (filtersAnnotation != null) {
     AnnotationInstance[] annotationInstances = filtersAnnotation.value().asNestedArray();
     for (AnnotationInstance filterAnnotation : annotationInstances) {
       FilterSource filterSource =
           new FilterSourceImpl(filterAnnotation, entityClass.getLocalBindingContext());
       filterSourceList.add(filterSource);
     }
   }
   AnnotationInstance filterAnnotation =
       JandexHelper.getSingleAnnotation(
           associationAttribute.annotations(), HibernateDotNames.FILTER);
   if (filterAnnotation != null) {
     FilterSource filterSource =
         new FilterSourceImpl(filterAnnotation, entityClass.getLocalBindingContext());
     filterSourceList.add(filterSource);
   }
   if (filterSourceList.isEmpty()) {
     return null;
   } else {
     return filterSourceList.toArray(new FilterSource[filterSourceList.size()]);
   }
 }
 @Override
 public FetchTiming getFetchTiming() {
   if (associationAttribute.isExtraLazy()) {
     return FetchTiming.EXTRA_LAZY;
   } else if (associationAttribute.isLazy()) {
     return FetchTiming.DELAYED;
   } else {
     return FetchTiming.IMMEDIATE;
   }
 }
 @Override
 public boolean usesJoinTable() {
   if (associationAttribute.getMappedBy() != null) {
     throw new IllegalStateException(
         "Cannot determine if a join table is used because plural attribute is not the owner.");
   }
   // By default, a unidirectional one-to-many (i.e., with mappedBy == null) uses a join table,
   // unless it has join columns defined.
   return associationAttribute.getJoinTableAnnotation() != null
       || (associationAttribute.getJoinTableAnnotation() == null
           && associationAttribute.getJoinColumnValues().size() == 0);
 }
 @Override
 public TableSpecificationSource getCollectionTableSpecificationSource() {
   // todo - see org.hibernate.metamodel.internal.Binder#bindOneToManyCollectionKey
   // todo - needs to cater for @CollectionTable and @JoinTable
   if (associationAttribute.getMappedBy() != null) {
     throw new IllegalStateException(
         "Cannot get collection table because this association is not the owner.");
   }
   final AnnotationInstance joinTableAnnotation = associationAttribute.getJoinTableAnnotation();
   return joinTableAnnotation == null
       ? null
       : new TableSourceImpl(joinTableAnnotation, entityClass.getLocalBindingContext());
 }
 private static PluralAttributeElementSource determineElementSource(
     AttributeSource ownerAttributeSource,
     PluralAttributeSourceImpl pluralAttributeSource,
     ConfiguredClass entityClass,
     String relativePath) {
   if (ownerAttributeSource == null) {
     throw new AssertionFailure("ownerAssociationSource must be non-null.");
   }
   final PluralAssociationAttribute associationAttribute =
       pluralAttributeSource.pluralAssociationAttribute();
   switch (pluralAttributeSource.pluralAssociationAttribute().getNature()) {
     case MANY_TO_MANY:
       return associationAttribute.getMappedBy() == null
           ? new ManyToManyPluralAttributeElementSourceImpl(
               pluralAttributeSource, relativePath, entityClass.getLocalBindingContext())
           : new ManyToManyMappedByPluralAttributeElementSourceImpl(
               pluralAttributeSource, relativePath);
     case MANY_TO_ANY:
       return new ManyToAnyPluralAttributeElementSourceImpl(pluralAttributeSource, relativePath);
     case ONE_TO_MANY:
       boolean usesJoinTable =
           ownerAttributeSource.isSingular()
               ? ((ToOneAttributeSource) ownerAttributeSource).getContainingTableName() != null
               : ((PluralAttributeSource) ownerAttributeSource).usesJoinTable();
       if (usesJoinTable) {
         return associationAttribute.getMappedBy() == null
             ? new ManyToManyPluralAttributeElementSourceImpl(
                 pluralAttributeSource, relativePath, entityClass.getLocalBindingContext())
             : new ManyToManyMappedByPluralAttributeElementSourceImpl(
                 pluralAttributeSource, relativePath);
       } else {
         return associationAttribute.getMappedBy() == null
             ? new OneToManyPluralAttributeElementSourceImpl(pluralAttributeSource, relativePath)
             : new OneToManyMappedByPluralAttributeElementSourceImpl(
                 pluralAttributeSource, relativePath);
       }
     case ELEMENT_COLLECTION_BASIC:
       return new BasicPluralAttributeElementSourceImpl(
           associationAttribute, entityClass, relativePath);
     case ELEMENT_COLLECTION_EMBEDDABLE:
       {
         // TODO: cascadeStyles?
         return new CompositePluralAttributeElementSourceImpl(
             associationAttribute, entityClass, relativePath);
       }
   }
   throw new AssertionError(
       "Unexpected attribute nature for a association:" + associationAttribute.getNature());
 }
 private static List<RelationalValueSource> createRelationalValueSources(
     PluralAssociationAttribute attribute) {
   AnnotationInstance columnAnnotation =
       JandexHelper.getSingleAnnotation(attribute.annotations(), HibernateDotNames.INDEX_COLUMN);
   if (columnAnnotation == null) {
     columnAnnotation =
         JandexHelper.getSingleAnnotation(attribute.annotations(), JPADotNames.ORDER_COLUMN);
   }
   if (columnAnnotation == null) {
     columnAnnotation =
         JandexHelper.getSingleAnnotation(attribute.annotations(), JPADotNames.MAP_KEY_COLUMN);
   }
   Column indexColumn = new Column(columnAnnotation);
   return Collections.singletonList((RelationalValueSource) new ColumnSourceImpl(indexColumn));
 }
 @Override
 public ValueHolder<Class<?>> getElementClassReference() {
   // needed for arrays
   Class<?> attributeType = associationAttribute.getAttributeType();
   if (attributeType.isArray()) {
     return new ValueHolder<Class<?>>(attributeType.getComponentType());
   } else {
     return null;
   }
 }
  public PluralAttributeSourceImpl(
      final PluralAssociationAttribute associationAttribute,
      final ConfiguredClass entityClass,
      final String relativePath) {
    this.associationAttribute = associationAttribute;
    this.entityClass = entityClass;
    this.keySource = new PluralAttributeKeySourceImpl(associationAttribute);
    this.typeSource = new HibernateTypeSourceImpl(associationAttribute);
    this.nature = associationAttribute.getPluralAttributeNature();
    this.attributePath =
        StringHelper.isEmpty(relativePath)
            ? associationAttribute.getName()
            : relativePath + "." + associationAttribute.getName();

    if (associationAttribute.getMappedBy() == null) {
      this.ownerAttributeSource = this;
      this.elementSource = determineElementSource(this, this, entityClass, attributePath);
    }
    this.filterSources = determineFilterSources(associationAttribute);
  }
 @Override
 public PluralAttributeElementSource resolvePluralAttributeElementSource(
     AttributeSourceResolutionContext context) {
   if (elementSource == null) {
     // elementSource has not been initialized, so we need to resolve it using the
     // association owner.
     // Get the owner attribute source that maps the opposite side of the association.
     ownerAttributeSource =
         context.resolveAttributeSource(
             associationAttribute.getReferencedEntityType(), associationAttribute.getMappedBy());
     // Initialize resolved entitySource.
     elementSource =
         determineElementSource(
             ownerAttributeSource,
             this,
             entityClass,
             ""); // TODO not sure what relativePath should be here
     if (!MappedByAssociationSource.class.isInstance(elementSource)) {
       throw new AssertionFailure("expected a mappedBy association.");
     }
     final AssociationSource ownerAssociationSource;
     if (ownerAttributeSource.isSingular()) {
       ownerAssociationSource = (ToOneAttributeSource) ownerAttributeSource;
     } else {
       final PluralAttributeSource pluralAttributeSource =
           (PluralAttributeSource) ownerAttributeSource;
       if (!AssociationSource.class.isInstance(pluralAttributeSource.getElementSource())) {
         throw new AssertionFailure("Owner is not an association.");
       }
       ownerAssociationSource = (AssociationSource) pluralAttributeSource.getElementSource();
     }
     ownerAssociationSource.addMappedByAssociationSource(
         (MappedByAssociationSource) elementSource);
   }
   return elementSource;
 }
 @Override
 public boolean isSorted() {
   return associationAttribute.isSorted();
 }
 @Override
 public String getComparatorName() {
   return associationAttribute.getComparatorName();
 }
 @Override
 public boolean isMutable() {
   return associationAttribute.isMutable();
 }
 @Override
 public String getOrder() {
   return elementSource.getNature() == PluralAttributeElementSource.Nature.MANY_TO_MANY
       ? null
       : associationAttribute.getOrderBy();
 }
 @Override
 public Caching getCaching() {
   return associationAttribute.getCaching();
 }
 @Override
 public CustomSQL getCustomSqlDeleteAll() {
   return associationAttribute.getCustomDeleteAll();
 }
 @Override
 public int getBatchSize() {
   return associationAttribute.getBatchSize();
 }
 @Override
 public CustomSQL getCustomSqlInsert() {
   return associationAttribute.getCustomInsert();
 }
 @Override
 public String getCustomLoaderName() {
   return associationAttribute.getCustomLoaderName();
 }
 @Override
 public String getMappedBy() {
   return associationAttribute.getMappedBy();
 }
 @Override
 public String getWhere() {
   return associationAttribute.getWhereClause();
 }
 @Override
 public String getCustomPersisterClassName() {
   return associationAttribute.getCustomPersister();
 }
 @Override
 public FetchStyle getFetchStyle() {
   return associationAttribute.getFetchStyle();
 }
 @Override
 public String getPropertyAccessorName() {
   return associationAttribute.getAccessType();
 }
 @Override
 public boolean isIncludedInOptimisticLocking() {
   return associationAttribute.isOptimisticLockable();
 }
 @Override
 public CustomSQL getCustomSqlUpdate() {
   return associationAttribute.getCustomUpdate();
 }
 @Override
 public String getCollectionTableCheck() {
   return associationAttribute.getCheckCondition();
 }