private void addFromProperties(
     Iterable<XProperty> properties,
     String accessType,
     Set<String> persistentProperties,
     Audited allClassAudited) {
   for (XProperty property : properties) {
     // If this is not a persistent property, with the same access type as currently checked,
     // it's not audited as well.
     // If the property was already defined by the subclass, is ignored by superclasses
     if (persistentProperties.contains(property.getName())
         && !auditedPropertiesHolder.contains(property.getName())) {
       final Value propertyValue =
           persistentPropertiesSource.getProperty(property.getName()).getValue();
       if (propertyValue instanceof Component) {
         this.addFromComponentProperty(
             property, accessType, (Component) propertyValue, allClassAudited);
       } else {
         this.addFromNotComponentProperty(property, accessType, allClassAudited);
       }
     } else if (propertiesGroupMapping.containsKey(property.getName())) {
       // Retrieve embedded component name based on class field.
       final String embeddedName = propertiesGroupMapping.get(property.getName());
       if (!auditedPropertiesHolder.contains(embeddedName)) {
         // Manage properties mapped within <properties> tag.
         final Value propertyValue =
             persistentPropertiesSource.getProperty(embeddedName).getValue();
         this.addFromPropertiesGroup(
             embeddedName, property, accessType, (Component) propertyValue, allClassAudited);
       }
     }
   }
 }
  private void addFromPropertiesGroup(
      String embeddedName,
      XProperty property,
      String accessType,
      Component propertyValue,
      Audited allClassAudited) {
    final ComponentAuditingData componentData = new ComponentAuditingData();
    final boolean isAudited =
        fillPropertyData(property, componentData, accessType, allClassAudited);
    if (isAudited) {
      // EntityPersister.getPropertyNames() returns name of embedded component instead of class
      // field.
      componentData.setName(embeddedName);
      // Marking component properties as placed directly in class (not inside another component).
      componentData.setBeanName(null);

      final PersistentPropertiesSource componentPropertiesSource =
          new ComponentPropertiesSource(reflectionManager, propertyValue);
      final AuditedPropertiesReader audPropReader =
          new AuditedPropertiesReader(
              ModificationStore.FULL,
              componentPropertiesSource,
              componentData,
              globalCfg,
              reflectionManager,
              propertyNamePrefix + MappingTools.createComponentPrefix(embeddedName));
      audPropReader.read();

      auditedPropertiesHolder.addPropertyAuditingData(embeddedName, componentData);
    }
  }
  private void addFromNotComponentProperty(
      XProperty property, String accessType, Audited allClassAudited) {
    final PropertyAuditingData propertyData = new PropertyAuditingData();
    final boolean isAudited = fillPropertyData(property, propertyData, accessType, allClassAudited);

    if (isAudited) {
      // Now we know that the property is audited
      auditedPropertiesHolder.addPropertyAuditingData(property.getName(), propertyData);
    }
  }
  /**
   * Recursively adds all audited properties of entity class and its superclasses.
   *
   * @param clazz Currently processed class.
   */
  private void addPropertiesFromClass(XClass clazz) {
    final Audited allClassAudited = computeAuditConfiguration(clazz);

    // look in the class
    addFromProperties(
        clazz.getDeclaredProperties("field"),
        "field",
        fieldAccessedPersistentProperties,
        allClassAudited);
    addFromProperties(
        clazz.getDeclaredProperties("property"),
        "property",
        propertyAccessedPersistentProperties,
        allClassAudited);

    if (allClassAudited != null || !auditedPropertiesHolder.isEmpty()) {
      final XClass superclazz = clazz.getSuperclass();
      if (!clazz.isInterface() && !"java.lang.Object".equals(superclazz.getName())) {
        addPropertiesFromClass(superclazz);
      }
    }
  }
  private void addFromComponentProperty(
      XProperty property, String accessType, Component propertyValue, Audited allClassAudited) {
    final ComponentAuditingData componentData = new ComponentAuditingData();
    final boolean isAudited =
        fillPropertyData(property, componentData, accessType, allClassAudited);

    if (propertyValue.isDynamic()) {
      if (isAudited) {
        throw new MappingException(
            "Audited dynamic-component properties are not supported. Consider applying @NotAudited annotation to "
                + propertyValue.getOwner().getEntityName()
                + "#"
                + property
                + ".");
      }
      return;
    }

    final PersistentPropertiesSource componentPropertiesSource =
        new ComponentPropertiesSource(reflectionManager, propertyValue);

    final ComponentAuditedPropertiesReader audPropReader =
        new ComponentAuditedPropertiesReader(
            ModificationStore.FULL,
            componentPropertiesSource,
            componentData,
            globalCfg,
            reflectionManager,
            propertyNamePrefix + MappingTools.createComponentPrefix(property.getName()));
    audPropReader.read();

    if (isAudited) {
      // Now we know that the property is audited
      auditedPropertiesHolder.addPropertyAuditingData(property.getName(), componentData);
    }
  }