/** INTERNAL: Recursive method to set a field value in the given key instance. */
  protected void setFieldValue(
      KeyElementAccessor accessor,
      Object keyInstance,
      DatabaseMapping mapping,
      AbstractSession session,
      int[] elementIndex,
      Object... keyElements) {
    if (mapping.isAggregateMapping()) {
      Object nestedObject = mapping.getRealAttributeValueFromObject(keyInstance, session);

      if (nestedObject == null) {
        nestedObject = getClassInstance(mapping.getReferenceDescriptor().getJavaClass());
        mapping.setRealAttributeValueInObject(keyInstance, nestedObject);
      }

      // keep drilling down the nested mappings ...
      setFieldValue(
          accessor,
          nestedObject,
          mapping
              .getReferenceDescriptor()
              .getObjectBuilder()
              .getMappingForField(accessor.getDatabaseField()),
          session,
          elementIndex,
          keyElements);
    } else {
      Object fieldValue = null;

      if (mapping.isDirectToFieldMapping()) {
        fieldValue = keyElements[elementIndex[0]];
        Converter converter = ((DirectToFieldMapping) mapping).getConverter();
        if (converter != null) {
          fieldValue = converter.convertDataValueToObjectValue(fieldValue, session);
        }
        ++elementIndex[0];
      } else if (mapping.isObjectReferenceMapping()) {
        // what if mapping comes from derived ID. need to get the derived mapping.
        // get reference descriptor and extract pk from target cmp policy
        fieldValue =
            mapping
                .getReferenceDescriptor()
                .getCMPPolicy()
                .createPrimaryKeyInstanceFromPrimaryKeyValues(session, elementIndex, keyElements);
      }

      accessor.setValue(keyInstance, fieldValue);
    }
  }
  /** INTERNAL: Create an instance of the Id class or value from the object. */
  public Object createPrimaryKeyInstance(Object object, AbstractSession session) {
    KeyElementAccessor[] pkElementArray = this.getKeyClassFields();
    ObjectBuilder builder = getDescriptor().getObjectBuilder();
    if (pkElementArray.length == 1 && pkElementArray[0] instanceof KeyIsElementAccessor) {
      DatabaseMapping mapping =
          builder.getMappingForAttributeName(pkElementArray[0].getAttributeName());
      Object fieldValue = mapping.getRealAttributeValueFromObject(object, session);
      if (mapping.isObjectReferenceMapping()) {
        fieldValue =
            mapping
                .getReferenceDescriptor()
                .getCMPPolicy()
                .createPrimaryKeyInstance(fieldValue, session);
      }
      return fieldValue;
    }

    Object keyInstance = getPKClassInstance();
    Set<ObjectReferenceMapping> usedObjectReferenceMappings = new HashSet<ObjectReferenceMapping>();
    for (int index = 0; index < pkElementArray.length; index++) {
      Object keyObj = object;
      KeyElementAccessor accessor = pkElementArray[index];
      DatabaseField field = accessor.getDatabaseField();
      DatabaseMapping mapping = builder.getMappingForField(field);
      // With session validation, the mapping shouldn't be null at this
      // point, don't bother checking.
      if (!mapping.isObjectReferenceMapping() || !usedObjectReferenceMappings.contains(mapping)) {
        while (mapping.isAggregateObjectMapping()) {
          keyObj = mapping.getRealAttributeValueFromObject(keyObj, session);
          mapping = mapping.getReferenceDescriptor().getObjectBuilder().getMappingForField(field);
        }
        Object fieldValue = mapping.getRealAttributeValueFromObject(keyObj, session);
        if (mapping.isObjectReferenceMapping()) {
          fieldValue =
              mapping
                  .getReferenceDescriptor()
                  .getCMPPolicy()
                  .createPrimaryKeyInstance(fieldValue, session);
          usedObjectReferenceMappings.add((ObjectReferenceMapping) mapping);
        }
        accessor.setValue(keyInstance, fieldValue);
      }
    }

    return keyInstance;
  }
  /**
   * INTERNAL: Create an instance of the composite primary key class for the key object. Yes the
   * elementIndex looks strange but this is just a simple way to get the index to be
   * pass-by-reference
   */
  public Object createPrimaryKeyInstanceFromPrimaryKeyValues(
      AbstractSession session, int[] elementIndex, Object... keyElements) {
    Object keyInstance = null;
    KeyElementAccessor[] pkElementArray = getKeyClassFields();
    if ((pkElementArray.length == 1) && (pkElementArray[0] instanceof KeyIsElementAccessor)) {
      DatabaseMapping mapping =
          getDescriptor()
              .getObjectBuilder()
              .getMappingForAttributeName(pkElementArray[0].getAttributeName());
      if (mapping.isDirectToFieldMapping()) {
        Converter converter = ((DirectToFieldMapping) mapping).getConverter();
        if (converter != null) {
          return converter.convertDataValueToObjectValue(keyElements[elementIndex[0]], session);
        }
        keyInstance = keyElements[elementIndex[0]];
      } else if (mapping
          .isObjectReferenceMapping()) { // what if mapping comes from derived ID.  need to get the
                                         // derived mapping.
        // get reference descriptor and extract pk from target cmp policy
        keyInstance =
            mapping
                .getReferenceDescriptor()
                .getCMPPolicy()
                .createPrimaryKeyInstanceFromPrimaryKeyValues(session, elementIndex, keyElements);
      }
      ++elementIndex[0]; // remove processed key in case keys are complex and derived
    } else {
      keyInstance = getPKClassInstance();
      // get clone of Key so we can remove values.
      for (int index = 0; index < pkElementArray.length; index++) {
        KeyElementAccessor accessor = pkElementArray[index];
        DatabaseMapping mapping =
            getDescriptor()
                .getObjectBuilder()
                .getMappingForAttributeName(accessor.getAttributeName());
        if (mapping == null) {
          mapping =
              getDescriptor().getObjectBuilder().getMappingForField(accessor.getDatabaseField());
        }

        if (accessor.isNestedAccessor()) {
          // Need to recursively build all the nested objects.
          setFieldValue(
              accessor,
              keyInstance,
              mapping
                  .getReferenceDescriptor()
                  .getObjectBuilder()
                  .getMappingForField(accessor.getDatabaseField()),
              session,
              elementIndex,
              keyElements);
        } else {
          // Not nested but may be a single layer aggregate so check.
          if (mapping.isAggregateMapping()) {
            mapping =
                mapping
                    .getReferenceDescriptor()
                    .getObjectBuilder()
                    .getMappingForField(accessor.getDatabaseField());
          }

          setFieldValue(accessor, keyInstance, mapping, session, elementIndex, keyElements);
        }
      }
    }

    return keyInstance;
  }