/** * @param value Value, which should be mapped to the middle-table, either as a relation to another * entity, or as a simple value. * @param xmlMapping If not <code>null</code>, xml mapping for this value is added to this * element. * @param queryGeneratorBuilder In case <code>value</code> is a relation to another entity, * information about it should be added to the given. * @param prefix Prefix for proeprty names of related entities identifiers. * @param joinColumns Names of columns to use in the xml mapping, if this array isn't null and has * any elements. * @return Data for mapping this component. */ @SuppressWarnings({"unchecked"}) private MiddleComponentData addValueToMiddleTable( Value value, Element xmlMapping, QueryGeneratorBuilder queryGeneratorBuilder, String prefix, JoinColumn[] joinColumns) { Type type = value.getType(); if (type instanceof ManyToOneType) { String prefixRelated = prefix + "_"; String referencedEntityName = MappingTools.getReferencedEntityName(value); IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData( referencingEntityName, referencedEntityName, propertyAuditingData, true); // Adding related-entity (in this case: the referenced entities id) id mapping to the xml only // if the // relation isn't inverse (so when <code>xmlMapping</code> is not null). if (xmlMapping != null) { addRelatedToXmlMapping( xmlMapping, prefixRelated, joinColumns != null && joinColumns.length > 0 ? MetadataTools.getColumnNameIterator(joinColumns) : MetadataTools.getColumnNameIterator(value.getColumnIterator()), referencedIdMapping); } // Storing the id data of the referenced entity: original mapper, prefixed mapper and entity // name. MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping, prefixRelated, referencedEntityName); // And adding it to the generator builder. queryGeneratorBuilder.addRelation(referencedIdData); return new MiddleComponentData( new MiddleRelatedComponentMapper(referencedIdData), queryGeneratorBuilder.getCurrentIndex()); } else { // Last but one parameter: collection components are always insertable boolean mapped = mainGenerator .getBasicMetadataGenerator() .addBasic( xmlMapping, new PropertyAuditingData( prefix, "field", ModificationStore.FULL, RelationTargetAuditMode.AUDITED, null, null, false), value, null, true, true); if (mapped) { // Simple values are always stored in the first item of the array returned by the query // generator. return new MiddleComponentData( new MiddleSimpleComponentMapper(mainGenerator.getVerEntCfg(), prefix), 0); } else { mainGenerator.throwUnsupportedTypeException(type, referencingEntityName, propertyName); // Impossible to get here. throw new AssertionError(); } } }
/** * Here is most of the nuts and bolts of this factory, where we interpret the known JPA metadata * against the known Hibernate metadata and build a descriptor for the attribute. * * @param attributeContext The attribute to be described * @param memberResolver Strategy for how to resolve the member defining the attribute. * @param <X> The owner type * @param <Y> The attribute type * @return The attribute description */ @SuppressWarnings({"unchecked"}) private <X, Y> AttributeMetadata<X, Y> determineAttributeMetadata( AttributeContext<X> attributeContext, MemberResolver memberResolver) { LOG.trace( "Starting attribute metadata determination [" + attributeContext.getPropertyMapping().getName() + "]"); final Member member = memberResolver.resolveMember(attributeContext); LOG.trace(" Determined member [" + member + "]"); final Value value = attributeContext.getPropertyMapping().getValue(); final org.hibernate.type.Type type = value.getType(); LOG.trace( " Determined type [name=" + type.getName() + ", class=" + type.getClass().getName() + "]"); if (type.isAnyType()) { // ANY mappings are currently not supported in the JPA metamodel; see HHH-6589 if (context.isIgnoreUnsupported()) { return null; } else { throw new UnsupportedOperationException("ANY not supported"); } } else if (type.isAssociationType()) { // collection or entity if (type.isEntityType()) { // entity return new SingularAttributeMetadataImpl<X, Y>( attributeContext.getPropertyMapping(), attributeContext.getOwnerType(), member, determineSingularAssociationAttributeType(member)); } // collection if (value instanceof Collection) { final Collection collValue = (Collection) value; final Value elementValue = collValue.getElement(); final org.hibernate.type.Type elementType = elementValue.getType(); // First, determine the type of the elements and use that to help determine the // collection type) final Attribute.PersistentAttributeType elementPersistentAttributeType; final Attribute.PersistentAttributeType persistentAttributeType; if (elementType.isAnyType()) { throw new UnsupportedOperationException("collection of any not supported yet"); } final boolean isManyToMany = isManyToMany(member); if (elementValue instanceof Component) { elementPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED; persistentAttributeType = Attribute.PersistentAttributeType.ELEMENT_COLLECTION; } else if (elementType.isAssociationType()) { elementPersistentAttributeType = isManyToMany ? Attribute.PersistentAttributeType.MANY_TO_MANY : Attribute.PersistentAttributeType.ONE_TO_MANY; persistentAttributeType = elementPersistentAttributeType; } else { elementPersistentAttributeType = Attribute.PersistentAttributeType.BASIC; persistentAttributeType = Attribute.PersistentAttributeType.ELEMENT_COLLECTION; } final Attribute.PersistentAttributeType keyPersistentAttributeType; // Finally, we determine the type of the map key (if needed) if (value instanceof Map) { final Value keyValue = ((Map) value).getIndex(); final org.hibernate.type.Type keyType = keyValue.getType(); if (keyType.isAnyType()) throw new UnsupportedOperationException("collection of any not supported yet"); if (keyValue instanceof Component) keyPersistentAttributeType = Attribute.PersistentAttributeType.EMBEDDED; else if (keyType.isAssociationType()) keyPersistentAttributeType = Attribute.PersistentAttributeType.MANY_TO_ONE; else keyPersistentAttributeType = Attribute.PersistentAttributeType.BASIC; } else keyPersistentAttributeType = null; return new PluralAttributeMetadataImpl( attributeContext.getPropertyMapping(), attributeContext.getOwnerType(), member, persistentAttributeType, elementPersistentAttributeType, keyPersistentAttributeType); } else if (value instanceof OneToMany) { // TODO : is this even possible??? Really OneToMany should be describing the // element value within a o.h.mapping.Collection (see logic branch above) throw new IllegalArgumentException("HUH???"); // final boolean isManyToMany = isManyToMany( member ); // //one to many with FK => entity // return new PluralAttributeMetadataImpl( // attributeContext.getPropertyMapping(), // attributeContext.getOwnerType(), // member, // isManyToMany // ? Attribute.PersistentAttributeType.MANY_TO_MANY // : Attribute.PersistentAttributeType.ONE_TO_MANY // value, // AttributeContext.TypeStatus.ENTITY, // Attribute.PersistentAttributeType.ONE_TO_MANY, // null, null, null // ); } } else if (attributeContext.getPropertyMapping().isComposite()) { // component return new SingularAttributeMetadataImpl<X, Y>( attributeContext.getPropertyMapping(), attributeContext.getOwnerType(), member, Attribute.PersistentAttributeType.EMBEDDED); } else { // basic type return new SingularAttributeMetadataImpl<X, Y>( attributeContext.getPropertyMapping(), attributeContext.getOwnerType(), member, Attribute.PersistentAttributeType.BASIC); } throw new UnsupportedOperationException( "oops, we are missing something: " + attributeContext.getPropertyMapping()); }