private String getMappedBy(Table collectionTable, PersistentClass referencedClass) { // If there's an @AuditMappedBy specified, returning it directly. String auditMappedBy = propertyAuditingData.getAuditMappedBy(); if (auditMappedBy != null) { return auditMappedBy; } // searching in referenced class String mappedBy = this.searchMappedBy(referencedClass, collectionTable); // not found on referenced class, searching on superclasses if (mappedBy == null) { LOG.debugf( "Going to search the mapped by attribute for %s in superclasses of entity: %s", propertyName, referencedClass.getClassName()); PersistentClass tempClass = referencedClass; while ((mappedBy == null) && (tempClass.getSuperclass() != null)) { LOG.debugf("Searching in superclass: %s", tempClass.getSuperclass().getClassName()); mappedBy = this.searchMappedBy(tempClass.getSuperclass(), collectionTable); tempClass = tempClass.getSuperclass(); } } if (mappedBy == null) { throw new MappingException( "Unable to read the mapped by attribute for " + propertyName + " in " + referencedClass.getClassName() + "!"); } return mappedBy; }
private String getMappedBy(Collection collectionValue) { PersistentClass referencedClass = null; if (collectionValue.getElement() instanceof OneToMany) { OneToMany oneToManyValue = (OneToMany) collectionValue.getElement(); referencedClass = oneToManyValue.getAssociatedClass(); } else if (collectionValue.getElement() instanceof ManyToOne) { // Case for bi-directional relation with @JoinTable on the owning @ManyToOne side. ManyToOne manyToOneValue = (ManyToOne) collectionValue.getElement(); referencedClass = manyToOneValue.getMappings().getClass(manyToOneValue.getReferencedEntityName()); } // If there's an @AuditMappedBy specified, returning it directly. String auditMappedBy = propertyAuditingData.getAuditMappedBy(); if (auditMappedBy != null) { return auditMappedBy; } // searching in referenced class String mappedBy = this.searchMappedBy(referencedClass, collectionValue); if (mappedBy == null) { LOG.debugf( "Going to search the mapped by attribute for %s in superclasses of entity: %s", propertyName, referencedClass.getClassName()); PersistentClass tempClass = referencedClass; while ((mappedBy == null) && (tempClass.getSuperclass() != null)) { LOG.debugf("Searching in superclass: %s", tempClass.getSuperclass().getClassName()); mappedBy = this.searchMappedBy(tempClass.getSuperclass(), collectionValue); tempClass = tempClass.getSuperclass(); } } if (mappedBy == null) { throw new MappingException( "Unable to read the mapped by attribute for " + propertyName + " in " + referencedClass.getClassName() + "!"); } return mappedBy; }
@SuppressWarnings({"unchecked"}) private void addWithMiddleTable() { LOG.debugf( "Adding audit mapping for property %s.%s: collection with a join table", referencingEntityName, propertyName); // Generating the name of the middle table String auditMiddleTableName; String auditMiddleEntityName; if (!StringTools.isEmpty(propertyAuditingData.getJoinTable().name())) { auditMiddleTableName = propertyAuditingData.getJoinTable().name(); auditMiddleEntityName = propertyAuditingData.getJoinTable().name(); } else { String middleTableName = getMiddleTableName(propertyValue, referencingEntityName); auditMiddleTableName = mainGenerator.getVerEntCfg().getAuditTableName(null, middleTableName); auditMiddleEntityName = mainGenerator.getVerEntCfg().getAuditEntityName(middleTableName); } LOG.debugf("Using join table name: %s", auditMiddleTableName); // Generating the XML mapping for the middle entity, only if the relation isn't inverse. // If the relation is inverse, will be later checked by comparing middleEntityXml with null. Element middleEntityXml; if (!propertyValue.isInverse()) { // Generating a unique middle entity name auditMiddleEntityName = mainGenerator.getAuditEntityNameRegister().createUnique(auditMiddleEntityName); // Registering the generated name mainGenerator.getAuditEntityNameRegister().register(auditMiddleEntityName); middleEntityXml = createMiddleEntityXml( auditMiddleTableName, auditMiddleEntityName, propertyValue.getWhere()); } else { middleEntityXml = null; } // ****** // Generating the mapping for the referencing entity (it must be an entity). // ****** // Getting the id-mapping data of the referencing entity (the entity that "owns" this // collection). IdMappingData referencingIdMapping = referencingEntityConfiguration.getIdMappingData(); // Only valid for an inverse relation; null otherwise. String mappedBy; // The referencing prefix is always for a related entity. So it has always the "_" at the end // added. String referencingPrefixRelated; String referencedPrefix; if (propertyValue.isInverse()) { // If the relation is inverse, then referencedEntityName is not null. mappedBy = getMappedBy( propertyValue.getCollectionTable(), mainGenerator.getCfg().getClassMapping(referencedEntityName)); referencingPrefixRelated = mappedBy + "_"; referencedPrefix = StringTools.getLastComponent(referencedEntityName); } else { mappedBy = null; referencingPrefixRelated = StringTools.getLastComponent(referencingEntityName) + "_"; referencedPrefix = referencedEntityName == null ? "element" : propertyName; } // Storing the id data of the referencing entity: original mapper, prefixed mapper and entity // name. MiddleIdData referencingIdData = createMiddleIdData(referencingIdMapping, referencingPrefixRelated, referencingEntityName); // Creating a query generator builder, to which additional id data will be added, in case this // collection // references some entities (either from the element or index). At the end, this will be used to // build // a query generator to read the raw data collection from the middle table. QueryGeneratorBuilder queryGeneratorBuilder = new QueryGeneratorBuilder( mainGenerator.getGlobalCfg(), mainGenerator.getVerEntCfg(), mainGenerator.getAuditStrategy(), referencingIdData, auditMiddleEntityName); // Adding the XML mapping for the referencing entity, if the relation isn't inverse. if (middleEntityXml != null) { // Adding related-entity (in this case: the referencing's entity id) id mapping to the xml. addRelatedToXmlMapping( middleEntityXml, referencingPrefixRelated, MetadataTools.getColumnNameIterator(propertyValue.getKey().getColumnIterator()), referencingIdMapping); } // ****** // Generating the element mapping. // ****** MiddleComponentData elementComponentData = addValueToMiddleTable( propertyValue.getElement(), middleEntityXml, queryGeneratorBuilder, referencedPrefix, propertyAuditingData.getJoinTable().inverseJoinColumns()); // ****** // Generating the index mapping, if an index exists. // ****** MiddleComponentData indexComponentData = addIndex(middleEntityXml, queryGeneratorBuilder); // ****** // Generating the property mapper. // ****** // Building the query generator. RelationQueryGenerator queryGenerator = queryGeneratorBuilder.build(elementComponentData, indexComponentData); // Creating common data CommonCollectionMapperData commonCollectionMapperData = new CommonCollectionMapperData( mainGenerator.getVerEntCfg(), auditMiddleEntityName, propertyAuditingData.getPropertyData(), referencingIdData, queryGenerator); // Checking the type of the collection and adding an appropriate mapper. addMapper(commonCollectionMapperData, elementComponentData, indexComponentData); // ****** // Storing information about this relation. // ****** storeMiddleEntityRelationInformation(mappedBy); }
@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); }