/** * INTERNAL: * Flags that either this mapping or nested mapping is a JPA id mapping. */ public boolean isJPAIdNested(AbstractSession session) { if (isJPAId()) { return true; } else { ClassDescriptor referenceDescriptor = getReferenceDescriptor(); if (referenceDescriptor == null) { // the mapping has not been initialized yet referenceDescriptor = session.getDescriptor(getReferenceClass()); } for (DatabaseMapping mapping : referenceDescriptor.getMappings()) { if (mapping.isAggregateObjectMapping() && ((AggregateObjectMapping)mapping).isJPAIdNested(session)) { return true; } } return false; } }
protected void addAggregateObjectMappingLines(NonreflectiveMethodDefinition method, String mappingName, AggregateObjectMapping mapping) { if (mapping.getReferenceClassName() != null) { method.addLine(mappingName + ".setReferenceClass(" + mapping.getReferenceClassName() + ".class);"); } method.addLine(mappingName + ".setIsNullAllowed(" + mapping.isNullAllowed() + ");"); for (Iterator<String> fieldTranslationEnum = mapping.getAggregateToSourceFields().keySet().iterator(); fieldTranslationEnum.hasNext();) { String aggregateFieldName = fieldTranslationEnum.next(); DatabaseField sourceField = mapping.getAggregateToSourceFields().get(aggregateFieldName); //may need to account for delimiting on the sourceField in the future method.addLine(mappingName + ".addFieldNameTranslation(\"" + sourceField.getQualifiedName() + "\", \"" + aggregateFieldName + "\");"); } }
/** * INTERNAL: * Clone the attribute from the original and assign it to the clone. */ public void buildClone(Object original, Object clone, UnitOfWorkImpl unitOfWork) { Object attributeValue = getAttributeValueFromObject(original); Object aggregateClone = buildClonePart(original, attributeValue, unitOfWork); if (aggregateClone != null) { ClassDescriptor descriptor = getReferenceDescriptor(aggregateClone, unitOfWork); descriptor.getObjectChangePolicy().setAggregateChangeListener(clone, aggregateClone, unitOfWork, descriptor, getAttributeName()); } setAttributeValueInObject(clone, aggregateClone); }
/** * INTERNAL: * Builds a shallow original object. Only direct attributes and primary * keys are populated. In this way the minimum original required for * instantiating a working copy clone can be built without placing it in * the shared cache (no concern over cycles). */ @Override public void buildShallowOriginalFromRow(AbstractRecord databaseRow, Object original, JoinedAttributeManager joinManager, ObjectBuildingQuery sourceQuery, AbstractSession executionSession) { Object aggregate = buildAggregateFromRow(databaseRow, original, null, joinManager, sourceQuery, true, executionSession, true);// shallow only. setAttributeValueInObject(original, aggregate); }
/** * INTERNAL: * Set the change listener in the aggregate. */ @Override public void setChangeListener(Object clone, PropertyChangeListener listener, UnitOfWorkImpl uow) { Object attributeValue = getAttributeValueFromObject(clone); if (attributeValue != null) { ClassDescriptor descriptor = getReferenceDescriptor(attributeValue, uow); descriptor.getObjectChangePolicy().setAggregateChangeListener(clone, attributeValue, uow, descriptor, getAttributeName()); } }
AbstractSession referenceSession = session; if( session.hasBroker()) { if (getReferenceClass() == null) { throw DescriptorException.referenceClassNotSpecified(this); referenceSession = session.getSessionForClass(getReferenceClass()); ClassDescriptor clonedDescriptor = (ClassDescriptor)getReferenceDescriptor().clone(); List<AttributeAccessor> accessorTree = getDescriptor().getAccessorTree(); if (accessorTree == null){ accessorTree = new ArrayList(); accessorTree.add(getAttributeAccessor()); clonedDescriptor.setAccessorTree(accessorTree); if (isMapKeyMapping() && clonedDescriptor.isAggregateDescriptor()){ clonedDescriptor.descriptorIsAggregateCollection(); initializeParentInheritance(parentDescriptor, clonedDescriptor, session); setReferenceDescriptor(clonedDescriptor); if (getReferenceDescriptor().hasTargetForeignKeyMapping(session)) { isNullAllowed = false; session.log(SessionLog.WARNING, SessionLog.METADATA, "metadata_warning_ignore_is_null_allowed", new Object[]{this}); initializeReferenceDescriptor(clonedDescriptor, referenceSession); translateNestedFields(clonedDescriptor, referenceSession);
Object aggregate = getAttributeValueFromObject(targetObject); ObjectChangeSet aggregateChangeSet = null; aggregate = readFromRowIntoObject(row, null, targetObject, null, query, query.getSession(), true); } else { if(changeSet != null && (!changeSet.isNew() || (query.getDescriptor() != null && query.getDescriptor().shouldUseFullChangeSetsForNewObjects()))) { aggregateChangeSet = getReferenceDescriptor(aggregate, query.getSession()).getObjectBuilder().createObjectChangeSet(aggregate, (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet(), true, query.getSession()); List fields = row.getFields(); List values = row.getValues(); List aggregateFields = getReferenceFields(); for(int i=0; i < size; i++) { DatabaseField field = (DatabaseField)fields.get(i); getObjectBuilder(aggregate, query.getSession()).assignReturnRow(aggregate, query.getSession(), aggregateRow, aggregateChangeSet); if (aggregate != null && isNullAllowed()) { boolean allAttributesNull = true; int nAggregateFields = this.fields.size(); allAttributesNull = row.get(field) == null; } else { Object fieldValue = valueFromObject(targetObject, field, query.getSession()); if (fieldValue == null) { Object baseValue = getDescriptor().getObjectBuilder().getBaseValueForField(field, targetObject); if (baseValue != null) { DatabaseMapping baseMapping = getDescriptor().getObjectBuilder().getBaseMappingForField(field); if (baseMapping.isForeignReferenceMapping()) { ForeignReferenceMapping refMapping = (ForeignReferenceMapping)baseMapping;
Object sopAggregate = getAttributeValueFromObject(databaseRow.getSopObject()); if ((targetObject != null) && (targetObject != databaseRow.getSopObject())) { setAttributeValueInObject(targetObject, sopAggregate); if (isNullAllowed() && allAggregateFieldsAreNull(databaseRow)) { return null; ClassDescriptor descriptor = getReferenceDescriptor(); boolean refreshing = true; if (targetObject != null){ if (descriptor.hasInheritance()) { Class newAggregateClass = descriptor.getInheritancePolicy().classFromRow(databaseRow, executionSession); descriptor = getReferenceDescriptor(newAggregateClass, executionSession); aggregate = getMatchingAttributeValueFromObject(databaseRow, targetObject, executionSession, descriptor); if ((aggregate != null) && (aggregate.getClass() != newAggregateClass)) { aggregate = getMatchingAttributeValueFromObject(databaseRow, targetObject, executionSession, descriptor); ObjectBuildingQuery nestedQuery = prepareNestedQuery(sourceQuery); FetchGroup targetFetchGroup = null; if (nestedQuery.isObjectLevelReadQuery()) { descriptor.getObjectBuilder().buildAttributesIntoShallowObject(aggregate, databaseRow, nestedQuery); } else if (executionSession.isUnitOfWork()) { descriptor.getObjectBuilder().buildAttributesIntoWorkingCopyClone(aggregate, buildWrapperCacheKeyForAggregate(cacheKey, targetIsProtected), nestedQuery, joinManager, databaseRow, (UnitOfWorkImpl)executionSession, refreshing); } else { descriptor.getObjectBuilder().buildAttributesIntoObject(aggregate, buildWrapperCacheKeyForAggregate(cacheKey, targetIsProtected), databaseRow, nestedQuery, joinManager, nestedQuery.getExecutionFetchGroup(descriptor), refreshing, executionSession);
if (isNullAllowed() && allAggregateFieldsAreNull(databaseRow)) { return null; ClassDescriptor descriptor = getReferenceDescriptor(); boolean refreshing = true; if (targetObject != null){ if (descriptor.hasInheritance()) { Class newAggregateClass = descriptor.getInheritancePolicy().classFromRow(databaseRow, executionSession); descriptor = getReferenceDescriptor(newAggregateClass, executionSession); aggregate = getMatchingAttributeValueFromObject(databaseRow, targetObject, executionSession, descriptor); if ((aggregate != null) && (aggregate.getClass() != newAggregateClass)) { aggregate = getMatchingAttributeValueFromObject(databaseRow, targetObject, executionSession, descriptor); if (((ObjectLevelReadQuery)nestedQuery).isPartialAttribute(getAttributeName()) || ((joinManager != null) && joinManager.isAttributeJoined(getDescriptor(), getAttributeName()))) { ((ObjectLevelReadQuery)nestedQuery).setPartialAttributeExpressions(extractNestedExpressions(((ObjectLevelReadQuery)sourceQuery).getPartialAttributeExpressions(), ((ObjectLevelReadQuery)nestedQuery).getExpressionBuilder(), false)); } else { ((ObjectLevelReadQuery)nestedQuery).getJoinedAttributeManager().setJoinedAttributeExpressions_(extractNestedExpressions(joinManager.getJoinedAttributeExpressions(), joinManager.getBaseExpressionBuilder(), false)); if (sourceQuery.isReadAllQuery() && ((ReadAllQuery)sourceQuery).isAttributeBatchRead(getDescriptor(), getAttributeName())) { ((ReadAllQuery)nestedQuery).setBatchReadAttributeExpressions(extractNestedExpressions(((ReadAllQuery)sourceQuery).getBatchReadAttributeExpressions(), ((ReadAllQuery)nestedQuery).getExpressionBuilder(), false));
/** * Add a {@link AggregateObjectMapping} ({@link Embeddable} in JPA) to the * {@link #entityType} being built or extended. * * @param name * attribute name to use in the dynamic entity. Also the property * name used to access the state of the entity * @param refType * dynamic type re[presenting the Embeddable/AggregateObject * @param allowsNull * true indicates that the attribute can be null if all values * are null. * @return the new mapping configured and initialized (if the descriptor has * been initialized). */ public AggregateObjectMapping addAggregateObjectMapping(String name, DynamicType refType, boolean allowsNull) { AggregateObjectMapping mapping = new AggregateObjectMapping(); mapping.setAttributeName(name); mapping.setReferenceClass(refType.getJavaClass()); mapping.setIsNullAllowed(allowsNull); return (AggregateObjectMapping) addMapping(mapping); }
/** * INTERNAL: * A combination of readFromRowIntoObject and buildClone. * <p> * buildClone assumes the attribute value exists on the original and can * simply be copied. * <p> * readFromRowIntoObject assumes that one is building an original. * <p> * Both of the above assumptions are false in this method, and actually * attempts to do both at the same time. * <p> * Extract value from the row and set the attribute to this value in the * working copy clone. * In order to bypass the shared cache when in transaction a UnitOfWork must * be able to populate working copies directly from the row. */ @Override public void buildCloneFromRow(AbstractRecord databaseRow, JoinedAttributeManager joinManager, Object clone, CacheKey sharedCacheKey, ObjectBuildingQuery sourceQuery, UnitOfWorkImpl unitOfWork, AbstractSession executionSession) { // This method is a combination of buildggregateFromRow and buildClonePart on the super class. // None of buildClonePart used, as not an orignal new object, nor do we worry about creating heavy clones for aggregate objects. // Ensure that the shared CacheKey is passed, as this will be set to null for a refresh of an invalid object. Object clonedAttributeValue = buildAggregateFromRow(databaseRow, clone, sharedCacheKey, joinManager, sourceQuery, false, executionSession, true); if (clonedAttributeValue != null) { ClassDescriptor descriptor = getReferenceDescriptor(clonedAttributeValue, unitOfWork); descriptor.getObjectChangePolicy().setAggregateChangeListener(clone, clonedAttributeValue, unitOfWork, descriptor, getAttributeName()); } setAttributeValueInObject(clone, clonedAttributeValue); }
if (attributeValue == null) { if (this.isNullAllowed) { if (backupAttributeValueIsNull(query)) { writeNullReferenceRow(record); } else if ((query.getBackupClone() != null) && ((getMatchingBackupAttributeValue(query, attributeValue) == null) || !(attributeValue.getClass().equals(getMatchingBackupAttributeValue(query, attributeValue).getClass())))) { getObjectBuilder(attributeValue, query.getSession()).buildRow(record, attributeValue, query.getSession()); } else { if (!query.getSession().isClassReadOnly(attributeValue.getClass())) { clonedQuery.setObject(attributeValue); if (query.getSession().isUnitOfWork()) { Object backupAttributeValue = getMatchingBackupAttributeValue(query, attributeValue); if (backupAttributeValue == null) { backupAttributeValue = getObjectBuilder(attributeValue, query.getSession()).buildNewInstance(); getObjectBuilder(attributeValue, query.getSession()).buildRowForUpdate(record, clonedQuery);
/** * INTERNAL: * Build a clone of the given element in a unitOfWork * @param element * @param unitOfWork * @param isExisting * @return */ public Object buildElementClone(Object attributeValue, Object parent, UnitOfWorkImpl unitOfWork, boolean isExisting){ Object aggregateClone = buildClonePart(attributeValue, unitOfWork, isExisting); if (aggregateClone != null) { ClassDescriptor descriptor = getReferenceDescriptor(aggregateClone, unitOfWork); descriptor.getObjectChangePolicy().setAggregateChangeListener(parent, aggregateClone, unitOfWork, descriptor, getAttributeName()); } return aggregateClone; }
if (databaseMapping.isAggregateObjectMapping()) { AggregateObjectMapping m = (AggregateObjectMapping) databaseMapping; Map<String, DatabaseField> mapping = m.getAggregateToSourceFields(); ClassDescriptor refDesc = descriptors.get(m.getReferenceClass()); for (DatabaseMapping refMapping : refDesc.getMappings()) { if (refMapping.isDirectToFieldMapping()) { if (!mapping.containsKey(refFieldName)) { DatabaseField mappedField = refDirectMapping.getField().clone(); mappedField.setName(m.getAttributeName() + "_" + mappedField.getName()); mapping.put(refFieldName, mappedField);
} else { clonedDescriptor.setDefaultTable(getDescriptor().getDefaultTable()); clonedDescriptor.setTables(getDescriptor().getTables()); clonedDescriptor.setPrimaryKeyFields(getDescriptor().getPrimaryKeyFields()); if (clonedDescriptor.hasTargetForeignKeyMapping(session) && !isJPAIdNested(session)) { for (DatabaseField pkField : getDescriptor().getPrimaryKeyFields()) { if (!getAggregateToSourceFields().containsKey(pkField.getName())) { if (this.getDescriptor().hasFetchGroupManager() && FetchGroupTracker.class.isAssignableFrom(clonedDescriptor.getJavaClass())){ if (clonedDescriptor.getFetchGroupManager() == null) { clonedDescriptor.setFetchGroupManager(new FetchGroupManager());
/** * PUBLIC: * If <em>all</em> the fields in the database row for the aggregate object are NULL, * then, by default, the mapping will place a null in the appropriate source object * (as opposed to an aggregate object filled with nulls). This behavior can be * explicitly set by calling #allowNull(). * To change this behavior, call #dontAllowNull(). Then the mapping * will build a new instance of the aggregate object that is filled with nulls * and place it in the source object. * In either situation, when writing, the mapping will place a NULL in all the * fields in the database row for the aggregate object. * * Note: Any aggregate that has a relationship mapping automatically does not allow * null. */ public void dontAllowNull() { setIsNullAllowed(false); }
/** * INTERNAL: * Indicates whether descriptor has at least one target foreign key mapping */ public boolean hasTargetForeignKeyMapping(AbstractSession session) { for (DatabaseMapping mapping: getMappings()) { if (mapping.isCollectionMapping() || (mapping.isObjectReferenceMapping() && !((ObjectReferenceMapping)mapping).isForeignKeyRelationship()) || mapping.isAbstractCompositeDirectCollectionMapping()) { return true; } else if (mapping.isAggregateObjectMapping()) { ClassDescriptor referenceDescriptor = ((AggregateObjectMapping)mapping).getReferenceDescriptor(); if (referenceDescriptor == null) { // the mapping has not been initialized yet referenceDescriptor = session.getDescriptor(((AggregateObjectMapping)mapping).getReferenceClass()); } if (referenceDescriptor.hasTargetForeignKeyMapping(session)) { return true; } } } return false; }
/** * INTERNAL: * Clone the aggregate to source field names. AggregateCollectionMapping * needs each nested embedded mapping to have its own list of aggregate * to source field names so that it can apply nested override names to * shared aggregate object mappings. */ @Override public Object clone() { AggregateObjectMapping mappingObject = (AggregateObjectMapping) super.clone(); Map<String, DatabaseField> aggregateToSourceFields = new HashMap<String, DatabaseField>(); aggregateToSourceFields.putAll(getAggregateToSourceFields()); mappingObject.setAggregateToSourceFields(aggregateToSourceFields); Map<String, Object[]> nestedTranslations = new HashMap<String, Object[]>(); nestedTranslations.putAll(getNestedFieldTranslations()); mappingObject.setNestedFieldTranslations(nestedTranslations); return mappingObject; }
/** * PUBLIC: * The classification type for the attribute this mapping represents */ @Override public Class getAttributeClassification() { return getReferenceClass(); }
@Override public void customizeColumnName(final String tableName, final AggregateObjectMapping databaseMapping, final Session session) { Map<String, DatabaseField> map = databaseMapping.getAggregateToSourceFields(); if (!map.isEmpty()) { logFine(session, "Seems there where annotations for AttributeOverride"); return; } else { Class<?> referenceClass = databaseMapping.getReferenceClass(); Field[] fields = referenceClass.getDeclaredFields(); if (fields.length > 0) { for (Field f : fields) { String fieldName = f.getName(); DatabaseField databaseField = new DatabaseField(); String databaseFieldName = NameUtils.buildFieldName(tableName, fieldName); databaseField.setName(databaseFieldName); map.put(fieldName.toUpperCase(), databaseField); logFine(session, "\tAggregate-Field " + fieldName + " --> " + databaseFieldName); } } } }