/** * @param mainGenerator Main generator, giving access to configuration and the basic mapper. * @param propertyValue Value of the collection, as mapped by Hibernate. * @param currentMapper Mapper, to which the appropriate {@link * org.hibernate.envers.entities.mapper.PropertyMapper} will be added. * @param referencingEntityName Name of the entity that owns this collection. * @param xmlMappingData In case this collection requires a middle table, additional mapping * documents will be created using this object. * @param propertyAuditingData Property auditing (meta-)data. Among other things, holds the name * of the property that references the collection in the referencing entity, the user data for * middle (join) table and the value of the <code>@MapKey</code> annotation, if there was one. */ public CollectionMetadataGenerator( AuditMetadataGenerator mainGenerator, Collection propertyValue, CompositeMapperBuilder currentMapper, String referencingEntityName, EntityXmlMappingData xmlMappingData, PropertyAuditingData propertyAuditingData) { this.mainGenerator = mainGenerator; this.propertyValue = propertyValue; this.currentMapper = currentMapper; this.referencingEntityName = referencingEntityName; this.xmlMappingData = xmlMappingData; this.propertyAuditingData = propertyAuditingData; this.propertyName = propertyAuditingData.getName(); referencingEntityConfiguration = mainGenerator.getEntitiesConfigurations().get(referencingEntityName); if (referencingEntityConfiguration == null) { throw new MappingException( "Unable to read auditing configuration for " + referencingEntityName + "!"); } referencedEntityName = MappingTools.getReferencedEntityName(propertyValue.getElement()); }
private String getMiddleTableName(Collection value, String entityName) { // We check how Hibernate maps the collection. if (value.getElement() instanceof OneToMany && !value.isInverse()) { // This must be a @JoinColumn+@OneToMany mapping. Generating the table name, as Hibernate // doesn't use a // middle table for mapping this relation. return StringTools.getLastComponent(entityName) + "_" + StringTools.getLastComponent(MappingTools.getReferencedEntityName(value.getElement())); } // Hibernate uses a middle table for mapping this relation, so we get it's name directly. return value.getCollectionTable().getName(); }
/** * @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(); } } }
@SuppressWarnings({"unchecked"}) private void addOneToManyAttached(boolean fakeOneToManyBidirectional) { LOG.debugf( "Adding audit mapping for property %s.%s: one-to-many collection, using a join column on the referenced entity", referencingEntityName, propertyName); String mappedBy = getMappedBy(propertyValue); IdMappingData referencedIdMapping = mainGenerator.getReferencedIdMappingData( referencingEntityName, referencedEntityName, propertyAuditingData, false); IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData(); // Generating the id mappers data for the referencing side of the relation. MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping, mappedBy + "_", referencingEntityName); // And for the referenced side. The prefixed mapper won't be used (as this collection isn't // persisted // in a join table, so the prefix value is arbitrary). MiddleIdData referencedIdData = createMiddleIdData(referencedIdMapping, null, referencedEntityName); // Generating the element mapping. MiddleComponentData elementComponentData = new MiddleComponentData(new MiddleRelatedComponentMapper(referencedIdData), 0); // Generating the index mapping, if an index exists. It can only exists in case a // javax.persistence.MapKey // annotation is present on the entity. So the middleEntityXml will be not be used. The // queryGeneratorBuilder // will only be checked for nullnes. MiddleComponentData indexComponentData = addIndex(null, null); // Generating the query generator - it should read directly from the related entity. RelationQueryGenerator queryGenerator = new OneAuditEntityQueryGenerator( mainGenerator.getGlobalCfg(), mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData, referencedEntityName, referencedIdData); // Creating common mapper data. CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData( mainGenerator.getVerEntCfg(), referencedEntityName, propertyAuditingData.getPropertyData(), referencingIdData, queryGenerator); PropertyMapper fakeBidirectionalRelationMapper; PropertyMapper fakeBidirectionalRelationIndexMapper; if (fakeOneToManyBidirectional) { // In case of a fake many-to-one bidirectional relation, we have to generate a mapper which // maps // the mapped-by property name to the id of the related entity (which is the owner of the // collection). String auditMappedBy = propertyAuditingData.getAuditMappedBy(); // Creating a prefixed relation mapper. IdMapper relMapper = referencingIdMapping .getIdMapper() .prefixMappedProperties(MappingTools.createToOneRelationPrefix(auditMappedBy)); fakeBidirectionalRelationMapper = new ToOneIdMapper( relMapper, // The mapper will only be used to map from entity to map, so no need to provide other // details // when constructing the PropertyData. new PropertyData(auditMappedBy, null, null, null), referencingEntityName, false); // Checking if there's an index defined. If so, adding a mapper for it. if (propertyAuditingData.getPositionMappedBy() != null) { String positionMappedBy = propertyAuditingData.getPositionMappedBy(); fakeBidirectionalRelationIndexMapper = new SinglePropertyMapper(new PropertyData(positionMappedBy, null, null, null)); // Also, overwriting the index component data to properly read the index. indexComponentData = new MiddleComponentData(new MiddleStraightComponentMapper(positionMappedBy), 0); } else { fakeBidirectionalRelationIndexMapper = null; } } else { fakeBidirectionalRelationMapper = null; fakeBidirectionalRelationIndexMapper = null; } // Checking the type of the collection and adding an appropriate mapper. addMapper(commonCollectionMapperData, elementComponentData, indexComponentData); // Storing information about this relation. referencingEntityConfiguration.addToManyNotOwningRelation( propertyName, mappedBy, referencedEntityName, referencingIdData.getPrefixedMapper(), fakeBidirectionalRelationMapper, fakeBidirectionalRelationIndexMapper); }